【Go】gorm学习
点击阅读更多查看文章内容
什么是ORM
ORM(Object-Relational Mapping,面向对象关系映射)是一种程序设计技术,它将面向对象编程中的对象和关系型数据库中的表格结构进行映射。通过ORM,开发者可以使用面向对象的方式来操作数据库,而不需要编写复杂的SQL语句。
具体来说,ORM提供了一个抽象层,允许开发者通过类和对象来表示数据库表和记录,通常这种映射是自动完成的,ORM框架会负责将对象的属性与数据库中的字段对应起来,并生成相应的SQL语句执行数据库操作。
go-gorm/gorm: The fantastic ORM library for Golang, aims to be developer friendly
GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.
gorm连接数据库
1 | package main |
生成表结构
db.AutoMigrate(&Product{}),根据Product结构体建表
1 | package main |
输出内容(实际执行语句)
执行结果:
模型
gorm.Model
在定义持久化模型 PO(persist object) 时,推荐组合使用 gorm.Model 中预定义的几个通用字段,包括主键、增删改时间等:
1 | type PO struct { |
值得一提的是,在 gorm 体系中,一个 po 模型只要启用了 deletedAt 字段,则默认会开启软删除机制:在执行删除操作时,不会立刻物理删除数据,而是仅仅将 po 的 deletedAt 字段置为非空.
标签
1 | type PO struct{ |
几类常用的标签及对应的用途展示如下表:
| 标签 | 作用 |
|---|---|
| primarykey | 主键 |
| unique_index | 唯一键 |
| index | 键 |
| auto_increment | 自增列 |
| column | 列名 |
| type | 列类型 |
| default | 默认值 |
| not null | 非空 |
零值
在 golang 中一些基础类型都存在对应的零值,即便用户未显式给字段赋值,字段在初始化时也会首先赋上零值. 比如 bool 类型的零值为 false;string 类型为 “”,int 类型为 0.
这样就会导致,在我们执行创建、更新等操作时,倘若 po 模型中存在零值字段,此时 gorm 无法区分到底是用户显式声明的零值,还是未显式声明而被编译器默认赋予的零值. 在无法区分的情况下,gorm 会统一按照后者,采取忽略处理的方式.
为什么只能更新非零值字段?如果我们去更新一个product 只设置了price:200,那么其他字段默认为零值,也就是说在更新数据库时会将其他字段都更新为零值,因此选择将零值忽略掉。
倘若此时我们想要明确是显式将字段设置为零值的,对应可以采取以下两种处理方式:
- 使用指针类型:
我们将 age 字段类型设定为 *int,只要指针非空,就代表使用方进行了显式赋值.
1 | type PO struct{ |
- 使用 sql.Nullxx 类型:
我们将 age 字段类型设定为 sql.NullInt64,只要 Valid 标识为 true,就代表使用方进行了显式赋值.
1 | type PO struct{ |
增删改查
1 | // 创建单个记录 |
1 | // 查询多个记录 |
1 | // 更新多个字段 |
1 | // 删除单个记录 |
在 GORM 中,表名通常是通过模型(结构体)自动推断的,而不是直接在语句中指定的。GORM 会根据模型的结构体名称和约定规则自动推断表名。
- 增:db.Create(&Product{Code: sql.NullString{“D42”, true}, Price: 100})
- INSERT INTO
products(created_at,updated_at,deleted_at,code,price) VALUES (‘2025-02-06 23:22:57.421’,’2025-02-06 23:22:57.421’,NULL,’D42’,100)
- INSERT INTO
- 删:db.Delete(&product) (删除product对应的id的记录)
- UPDATE
productsSETdeleted_at=’2025-02-06 23:26:32.629’ WHEREproducts.id= 3 ANDproducts.deleted_atIS NULL
- UPDATE
- 改:db.Model(&product).Update(“Price”, 200) (修改product对应的id的记录)
- UPDATE
productsSETprice=200,updated_at=’2025-02-06 23:24:49.857’ WHEREid= 3
- UPDATE
- 查:db.First(&product, “code = ?”, “D42”) (查找 code 字段值为 D42 的记录 赋值给 product)
- SELECT * FROM
productsWHERE code = ‘D42’ ANDproducts.deleted_atIS NULL ORDER BYproducts.idLIMIT 1
- SELECT * FROM
表结构定义细节
通过字段标签声明表结构定义的细节(字段标签)
定义user表
- 将userid设为主键
- 将name列名设置为user_name,类型设置为varchar(50),设置索引idx_user_name,设置唯一索引,设置默认值“bobby”
1 | type User struct { |
插入记录
1 | user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()} |
批量插入
要高效地插入大量记录,请将切片传递给Create方法。 GORM 将生成一条 SQL 来插入所有数据
1 | var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}} |
你可以通过db.CreateInBatches方法来指定批量插入的批次大小,以下代币会执行两次insert,第一次插入两条,第二次插入一条
sql语句有长度限制,一次性插入的数据是有上限的,所以需要限制每次插入的数量
1 | var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}} |
通过map插入
GORM支持通过 map[string]interface{} 与 []map[string]interface{}{}来创建记录。
1 | db.Model(&User{}).Create(map[string]interface{}{ |
查询记录
检索单个对象
GORM 提供了 First、Take、Last 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件,且没有找到记录时,它会返回 ErrRecordNotFound 错误
1 | var user User |
检索全部对象
1 | var users []User |
gorm的基本查询
String 条件
where设置查询条件,First指定表名以及limit 1,find不会添加limit
1 | // Get first matched record |
Struct & Map 条件
1 | // Struct |
更新记录
Save更新
Save 会保存所有的字段,即使字段是零值
1 | db.First(&user) |
Save 是一个组合函数。 如果保存值不包含主键,它将执行 Create,否则它将执行 Update (包含所有字段)。
1 | db.Save(&User{Name: "jinzhu", Age: 100}) |
更新单个列
Model中传入空的User则指定表名,如果user有值则传入where子句
1 | // 根据条件更新 |
gorm的软删除细节
删除一条记录时,删除对象需要指定主键,否则会触发 批量删除,例如:
1 | // Email 的 ID 是 `10` |
软删除
如果你的模型包含了 gorm.DeletedAt字段(该字段也被包含在gorm.Model中),那么该模型将会自动获得软删除的能力!
当调用Delete时,GORM并不会从数据库中删除该记录,而是将该记录的DeleteAt设置为当前时间,而后的一般查询方法将无法查找到此条记录。
1 | // user's ID is `111` |
如果你并不想嵌套gorm.Model,你也可以像下方例子那样开启软删除特性:
1 | type User struct { |
查找被软删除的记录
你可以使用Unscoped来查询到被软删除的记录
1 | db.Unscoped().Where("age = 20").Find(&users) |
永久删除
你可以使用 Unscoped来永久删除匹配的记录
1 | db.Unscoped().Delete(&order) |

