Golang学习笔记之GORM基础使用(二)
本文章主要学习GORM的增删查改。若还没有完成数据库和数据表的创建、定义模型以及数据库的连接请先学习本本专栏文章Golang学习笔记之GORM基础使用(一)。本文为学习笔记,通过GORM官方中文文档和李文周的博客学习整理而成。
也可以使用原生sql语句。当然使用orm语句的便利点在于切换,可以切换不同的数据库。
目录
创建记录
官方文档创建链接:
创建 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.https://gorm.io/zh_CN/docs/create.html小技巧:在学习过程中要是有不理解的步骤可以通过Debug()(例如db.Debug().Create(&User))可以打印出对应的sql语句更好理解。
基本操作
1、先在代码层面创建一个User对象,此时数据中是没有这一条数据的。
2、使用db.Create()进行创建。注意在括号中要使用指针。
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()} //在代码层面创建一个User对象
result := db.Create(&user) // 通过数据的指针来创建
user.ID // 返回插入数据的主键
result.Error // 返回 error
result.RowsAffected // 返回插入记录的条数
3、可以使用下述代码判断主键是否为空。通过返回值可以判断如果主键为空可以直接创建,若不为空说明该条数据已经存在,可以选择更改数据或者不做更改。
db.NewRecord(&user)
默认值
在用户不传递这个值的时候就使用默认值进行代替。也就是所有字段的零值,比如0
, ""
,false
或者其它零值
,都不会保存到数据库内,但会使用他们的默认值。
`gorm:"default:'xka'"`
放在代码中如下位置:
// UserInfo 用户信息
type UserInfo struct {
ID uint
Name string `gorm:"default:'xka'"` //在name字段为空时,使用xka代替
Gender string
Hobby string
}
//表示配置操作数据库的表名称,如果没有表名则是直接使用结构体的复数
func (UserInfo) TableName() string {
return "userinfo"
}
注意:通过tag定义字段的默认值,在创建记录时候生成的 SQL 语句会排除没有值或值为 零值 的字段。 在将记录插入到数据库后,Gorm会从数据库加载那些字段的默认值。
若是设置了默认值之后想要保留空字符串时,可以考虑使用指针或实现 Scanner/Valuer
接口。
1、使用指针方式
// 使用指针
type UserInfo struct {
ID uint
Name *string `gorm:"default:'xka'"` //使用的是字符串的指针*string
Gender string
Hobby string
}
user := User{Name: new(string), Age: 18))} //new(string)空字符串的指针
db.Create(&user) // 此时数据库中该条记录name字段的值就是''
2、使用实现 Scanner/Valuer
接口
type UserInfo struct {
ID uint
Name sql.NullString `gorm:"default:'xka'"` // sql.NullString 实现了Scanner/Valuer接口
Gender string
Hobby string
}
user := User{Name: sql.NullString{"", true}, Age:18}
db.Create(&user) // 此时数据库中该条记录name字段的值就是''
查询操作
官方文档查询链接:
查询 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.https://gorm.io/zh_CN/docs/query.html GORM 提供了 First
、Take
、Last
方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1
条件,且没有找到记录时,它会返回 ErrRecordNotFound
错误
基本查询
注意:以下几种要以id作为主键。
var user User
var users []User
// 获取第一条记录(主键升序)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;
// 获取一条记录,没有指定排序字段
db.Take(&user)
// SELECT * FROM users LIMIT 1;
// 获取最后一条记录(主键降序)
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;
// 查询所有的记录
db.Find(&users)
SELECT * FROM users;
// 查询指定的某条记录(仅当主键为整型时可用)
db.First(&user, 10)
SELECT * FROM users WHERE id = 10;
result := db.First(&user)
result.RowsAffected // 返回找到的记录数
result.Error // returns error or nil
// 检查 ErrRecordNotFound 错误
errors.Is(result.Error, gorm.ErrRecordNotFound)
条件查询Where
// Get first matched record
db.Where("name = ?", "xka").First(&user)
SELECT * FROM users WHERE name = 'xka' limit 1;
// Get all matched records
db.Where("name = ?", "xka").Find(&users)
SELECT * FROM users WHERE name = 'xka';
// <>不等于
db.Where("name <> ?", "xka").Find(&users)
SELECT * FROM users WHERE name <> 'xka';
// IN在一个范围里面
db.Where("name IN (?)", []string{"xka", "xka2"}).Find(&users)
SELECT * FROM users WHERE name in ('xka','xka2');
// LIKE模糊查询
db.Where("name LIKE ?", "%xk%").Find(&users)
SELECT * FROM users WHERE name LIKE '%xk%';
// AND
db.Where("name = ? AND age >= ?", "xka", "22").Find(&users)
SELECT * FROM users WHERE name = 'xka' AND age >= 22;
// Time
db.Where("updated_at > ?", lastWeek).Find(&users)
SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00';
// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';
结构体和Map查询
// Struct
db.Where(&User{Name: "xka", Age: 20}).First(&user)
SELECT * FROM users WHERE name = "xka" AND age = 20 LIMIT 1;
// Map
db.Where(map[string]interface{}{"name": "xka", "age": 20}).Find(&users)
SELECT * FROM users WHERE name = "xka" AND age = 20;
// 主键的切片
db.Where([]int64{20, 21, 22}).Find(&users)
SELECT * FROM users WHERE id IN (20, 21, 22);
注意:当通过结构体进行查询时,GORM将会只通过非零值字段查询,这意味着如果你的字段值为0
,''
,false
或者其他零值
时,将不会被用于构建查询条件。例如:
db.Where(&User{Name: "xka", Age: 0}).Find(&users)
// SELECT * FROM users WHERE name = "xka";
//age=0没有作为条件参与sql语句
查询零值条件
可以使用指针或实现Scanner/Valuer接口来避免这个问题。
1、使用指针
// 使用指针
type User struct {
gorm.Model
Name string
Age *int
}
2、使用Scanner/Valuer接口
// 使用 Scanner/Valuer
type User struct {
gorm.Model
Name string
Age sql.NullInt64 // sql.NullInt64 实现了 Scanner/Valuer 接口
}
NOT条件
作用与Where类似的情形如下:
db.Not("name", "jinzhu").First(&user)
SELECT * FROM users WHERE name <> "jinzhu" LIMIT 1;
// Not In
db.Not("name", []string{"jinzhu", "jinzhu 2"}).Find(&users)
SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");
// Not In slice of primary keys
db.Not([]int64{1,2,3}).First(&user)
SELECT * FROM users WHERE id NOT IN (1,2,3);
db.Not([]int64{}).First(&user)
SELECT * FROM users;
// Plain SQL
db.Not("name = ?", "jinzhu").First(&user)
SELECT * FROM users WHERE NOT(name = "jinzhu");
// Struct
db.Not(User{Name: "jinzhu"}).First(&user)
SELECT * FROM users WHERE name <> "jinzhu";
Or条件
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';
// Struct
db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2"}).Find(&users)
SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';
// Map
db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2"}).Find(&users)
SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';
内联条件
作用与Where
查询类似,当内联条件与多个立即执行方法一起使用时, 内联条件不会传递给后面的立即执行方法(解释见下)。
立即执行方法:Immediate methods ,立即执行方法是指那些会立即生成SQL
语句并发送到数据库的方法, 他们一般是CRUD
方法,比如:Create
, First
, Find
, Take
, Save
, Update
, Delete
, Scan
, Row
…
// 根据主键获取记录 (只适用于整形主键)
db.First(&user, 23)
SELECT * FROM users WHERE id = 23 LIMIT 1;
// 根据主键获取记录, 如果它是一个非整形主键
db.First(&user, "id = ?", "string_primary_key")
SELECT * FROM users WHERE id = 'string_primary_key' LIMIT 1;
// Plain SQL
db.Find(&user, "name = ?", "jinzhu")
SELECT * FROM users WHERE name = "jinzhu";
db.Find(&users, "name <> ? AND age > ?", "jinzhu", 20)
SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;
// Struct
db.Find(&users, User{Age: 20})
SELECT * FROM users WHERE age = 20;
// Map
db.Find(&users, map[string]interface{}{"age": 20})
SELECT * FROM users WHERE age = 20;
额外查询选项
// 为查询 SQL 添加额外的 SQL 操作
db.Set("gorm:query_option", "FOR UPDATE").First(&user, 10)
SELECT * FROM users WHERE id = 10 FOR UPDATE;
注:for update是一种行级锁,又叫排它锁,一旦用户对某个行施加了行级加锁,则该用户可以查询也可以更新被加锁的数据行,其它用户只能查询但不能更新被加锁的数据行.
FirstOrInit
获取匹配的第一条记录,否则根据给定的条件初始化一个新的对象 (仅支持 struct 和 map 条件)
// 未找到
db.FirstOrInit(&user, User{Name: "non_existing"})
user -> User{Name: "non_existing"}
// 找到
db.Where(User{Name: "xka"}).FirstOrInit(&user)
user -> User{Id: 111, Name: "xka", Age: 20}
db.FirstOrInit(&user, map[string]interface{}{"name": "xka"})
user -> User{Id: 111, Name: "xka", Age: 20}
Attrs(找不到时使用)
如果记录未找到,将使用参数初始化 struct. 给新建的对象添加其他属性值。
// 未找到
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&user)
SELECT * FROM USERS WHERE name = 'non_existing';
user -> User{Name: "non_existing", Age: 20}
db.Where(User{Name: "non_existing"}).Attrs("age", 20).FirstOrInit(&user)
SELECT * FROM USERS WHERE name = 'non_existing';
user -> User{Name: "non_existing", Age: 20}
// 找到
db.Where(User{Name: "xka"}).Attrs(User{Age: 30}).FirstOrInit(&user)
SELECT * FROM USERS WHERE name = xka';
user -> User{Id: 111, Name: "xka", Age: 20}
Assign(不管找不找到都是用)
不管记录是否找到,都将参数赋值给struct。
// 未找到
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user)
user -> User{Name: "non_existing", Age: 20}
// 找到
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 30}).FirstOrInit(&user)
SELECT * FROM USERS WHERE name = jinzhu';
user -> User{Id: 111, Name: "Jinzhu", Age: 30}
FirstOrCreate
获取匹配的第一条记录, 否则根据给定的条件创建一个新的记录 (仅支持 struct 和 map 条件)
// 未找到
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
SELECT * FROM users WHERE name = 'non_existing';
INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
user -> User{Id: 112, Name: "non_existing", Age: 20}
// 找到
db.Where(User{Name: "jinzhu"}).Attrs(User{Age: 30}).FirstOrCreate(&user)
SELECT * FROM users WHERE name = 'jinzhu';
user -> User{Id: 111, Name: "jinzhu", Age: 20}
Attrs(找不到时使用)
如果记录未找到,将使用参数初始化 struct. 给新建的对象添加其他属性值。
// 未找到
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
SELECT * FROM users WHERE name = 'non_existing';
INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
user -> User{Id: 112, Name: "non_existing", Age: 20}
// 找到
db.Where(User{Name: "jinzhu"}).Attrs(User{Age: 30}).FirstOrCreate(&user)
SELECT * FROM users WHERE name = 'jinzhu';
user -> User{Id: 111, Name: "jinzhu", Age: 20}
Assign(不管找不找到都是用)
不管记录是否找到,都将参数赋值给struct。
// 未找到
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrCreate(&user)
SELECT * FROM users WHERE name = 'non_existing';
INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
user -> User{Id: 112, Name: "non_existing", Age: 20}
// 找到
db.Where(User{Name: "xka"}).Assign(User{Age: 30}).FirstOrCreate(&user)
SELECT * FROM users WHERE name = 'xka';
UPDATE users SET age=30 WHERE id = 111;
user -> User{Id: 111, Name: "xka", Age: 30}
检索相应字段
Select,指定你想从数据库中检索出的字段,默认会选择全部字段。
db.Select("name, age").Find(&users)
SELECT name, age FROM users;
db.Select([]string{"name", "age"}).Find(&users)
SELECT name, age FROM users;
db.Table("users").Select("COALESCE(age,?)", 42).Rows()
SELECT COALESCE(age,'42') FROM users;
排序
db.Order("age desc, name").Find(&users)
SELECT * FROM users ORDER BY age desc, name;
// 多字段排序
db.Order("age desc").Order("name").Find(&users)
SELECT * FROM users ORDER BY age desc, name;
// 覆盖排序
db.Order("age desc").Find(&users1).Order("age", true).Find(&users2)
SELECT * FROM users ORDER BY age desc; (users1)
SELECT * FROM users ORDER BY age; (users2)
数量
db.Limit(3).Find(&users)
SELECT * FROM users LIMIT 3;
// -1 取消 Limit 条件
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
SELECT * FROM users LIMIT 10; (users1)
SELECT * FROM users; (users2)
偏移
Offset,指定开始返回记录前要跳过的记录数。
db.Offset(3).Find(&users)
SELECT * FROM users OFFSET 3;
// -1 取消 Offset 条件
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
SELECT * FROM users OFFSET 10; (users1)
SELECT * FROM users; (users2)
总数
Count,该 model 能获取的记录总数。
db.Where("name = ?", "xka").Or("name = ?", "xka2").Find(&users).Count(&count)
SELECT * from USERS WHERE name = 'xka' OR name = 'xka2'; (users)
SELECT count(*) FROM users WHERE name = 'xka' OR name = 'xka2'; (count)
db.Model(&User{}).Where("name = ?", "xka").Count(&count)
SELECT count(*) FROM users WHERE name = 'xka'; (count)
db.Table("deleted_users").Count(&count)
SELECT count(*) FROM deleted_users;
db.Table("deleted_users").Select("count(distinct(name))").Count(&count)
SELECT count( distinct(name) ) FROM deleted_users; (count)
注意 :Count
必须是链式查询的最后一个操作 ,因为它会覆盖前面的 SELECT
,但如果里面使用了 count
时不会覆盖
更新操作
官方中文文档:
保存所有字段
Save
会保存所有的字段,即使字段是零值
//从数据库中查询出需要更改的数据
db.First(&user)
//给user修改值
user.Name = "jinzhu 2"
user.Age = 100
//将修改值保存到数据库中
db.Save(&user)
// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;
更新单个列
当使用 Update
更新单列时,需要有一些条件,否则将会引起错误 ErrMissingWhereClause
,阻止全局更新。当使用 Model
方法,并且值中有主键值时,主键将会被用于构建条件。
阻止全局更新 :如果在没有任何条件的情况下执行批量更新,默认情况下,GORM 不会执行该操作,并返回 ErrMissingWhereClause
错误。对此,你必须加一些条件,或者使用原生 SQL,或者启用 AllowGlobalUpdate
模式
// 条件更新
db.Model(&User{}).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE active=true;
// User 的 ID 是 `111`
db.Model(&user).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;
// 根据条件和 model 的值进行更新
db.Model(&user).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;
更新多列
Updates
方法支持 struct
和 map[string]interface{}
参数。当使用 struct
更新时,默认情况下,GORM 只会更新非零值的字段
// 根据 `struct` 更新属性,只会更新非零值的字段
db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;
// 根据 `map` 更新属性
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello', age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;
更新选定字段
更新时选定、忽略某些字段,您可以使用 Select
、Omit
// Select with Map
// User's ID is `111`:
db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello' WHERE id=111;
db.Model(&user).Omit("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;
// Select with Struct (select zero value fields)
db.Model(&user).Select("Name", "Age").Updates(User{Name: "new_name", Age: 0})
// UPDATE users SET name='new_name', age=0 WHERE id=111;
// Select all fields (select all fields include zero value fields)
db.Model(&user).Select("*").Updates(User{Name: "jinzhu", Role: "admin", Age: 0})
// Select all fields but omit Role (select all fields include zero value fields)
db.Model(&user).Select("*").Omit("Role").Updates(User{Name: "jinzhu", Role: "admin", Age: 0})
更新 Hook
Hook :对象生命周期,Hook 是在创建、查询、更新、删除等操作之前、之后调用的函数。如果您已经为模型定义了指定的方法,它会在创建、更新、查询、删除时自动被调用。如果任何回调返回错误,GORM 将停止后续的操作并回滚事务。(事务)
func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
if u.readonly() {
err = errors.New("read only user")
}
return
}
// 在同一个事务中更新数据
func (u *User) AfterUpdate(tx *gorm.DB) (err error) {
if u.Confirmed {
tx.Model(&Address{}).Where("user_id = ?", u.ID).Update("verfied", true)
}
return
}
无Hooks更新
上面的更新操作会自动运行 model 的 BeforeUpdate
, AfterUpdate
方法,更新 UpdatedAt
时间戳, 在更新时保存其 Associations
, 如果你不想调用这些方法,你可用 UpdateColumn,
UpdateColumns
// 更新单个属性,类似于 `Update`
db.Model(&user).UpdateColumn("name", "hello")
UPDATE users SET name='hello' WHERE id = 111;
// 更新多个属性,类似于 `Updates`
db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
UPDATE users SET name='hello', age=18 WHERE id = 111;
批量更新
如果您尚未通过 Model
指定记录的主键,则 GORM 会执行批量更新。
// 根据 struct 更新
db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE role = 'admin';
// 根据 map 更新
db.Table("users").Where("id IN ?", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18})
// UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);
使用 struct 更新时,只会更新非零值字段,若想更新所有字段,请使用map[string]interface{}。
db.Table("users").Where("id IN (?)", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18})
UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);
// 使用 struct 更新时,只会更新非零值字段,若想更新所有字段,请使用map[string]interface{}
db.Model(User{}).Updates(User{Name: "hello", Age: 18})
UPDATE users SET name='hello', age=18;
// 使用 `RowsAffected` 获取更新记录总数
db.Model(User{}).Updates(User{Name: "hello", Age: 18}).RowsAffected
删除操作
官方中文文档:
基本删除
注意:删除记录时,请确保主键字段有值,GORM 会通过主键去删除记录,如果主键为空,GORM 会删除该 model 的所有记录。
此处的email已经提前有了id值。
// 删除现有记录
db.Delete(&email)
DELETE from emails where id=10;
// 为删除 SQL 添加额外的 SQL 操作
db.Set("gorm:delete_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Delete(&email)
DELETE from emails where id=10 OPTION (OPTIMIZE FOR UNKNOWN);
根据主键删除
db.Delete(&User{}, 10)
// DELETE FROM users WHERE id = 10;
db.Delete(&User{}, "10")
// DELETE FROM users WHERE id = 10;
db.Delete(&users, []int{1,2,3})
// DELETE FROM users WHERE id IN (1,2,3);
Delete Hook
对于删除操作,GORM 支持 BeforeDelete
、AfterDelete
Hook,在删除记录时会调用这些方法 。
// 在同一个事务中更新数据
func (u *User) AfterDelete(tx *gorm.DB) (err error) {
if u.Confirmed {
tx.Model(&Address{}).Where("user_id = ?", u.ID).Update("invalid", false)
}
return
}
批量删除
如果指定的值不包括主属性,那么 GORM 会执行批量删除,它将删除所有匹配的记录。
db.Where("email LIKE ?", "%jinzhu%").Delete(&Email{})
// DELETE from emails where email LIKE "%jinzhu%";
db.Delete(&Email{}, "email LIKE ?", "%jinzhu%")
// DELETE from emails where email LIKE "%jinzhu%";
阻止全局删除
如果没有任何条件的情况下执行批量删除,GORM 不会执行该操作,返回ErrMissingWhereClaus
错误。对此,你必须加一些条件,或者使用原生 SQL,或者启用 AllowGlobalUpdate
模式。
db.Delete(&User{}).Error // gorm.ErrMissingWhereClause
db.Where("1 = 1").Delete(&User{})
// DELETE FROM `users` WHERE 1=1
db.Exec("DELETE FROM users")
// DELETE FROM users
db.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{})
// DELETE FROM users
软删除
如果您的模型包含了一个 gorm.deletedat
字段(gorm.Model
已经包含了该字段),它将自动获得软删除的能力!拥有软删除能力的模型调用 Delete
时,记录不会从数据库被真正删除。但 GORM会将 DeletedAt
置为当前时间, 并且你不能再通过普通的查询方法找到该记录。
// user 的 ID 是 `111`
db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// 批量删除
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
// 在查询时会忽略被软删除的记录
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
如果不想引入 gorm.Model
,可以这样启用软删除特性:
type User struct {
ID int
Deleted gorm.DeletedAt
Name string
}
查找被软删除的记录
可使用 Unscoped
找到被软删除的记录 。
db.Unscoped().Where("age = 20").Find(&users)
// SELECT * FROM users WHERE age = 20;
以上就是本次所有关于GORM的增删查改的学习,谢谢观看!如有什么错误请各位大神在评论区指出。