Golang学习笔记之GORM基础使用(二)

本文章主要学习GORM的增删查改。若还没有完成数据库和数据表的创建、定义模型以及数据库的连接请先学习本本专栏文章Golang学习笔记之GORM基础使用(一)。本文为学习笔记,通过GORM官方中文文档和李文周的博客学习整理而成。

也可以使用原生sql语句。当然使用orm语句的便利点在于切换,可以切换不同的数据库。

目录

创建记录

基本操作 

默认值 

查询操作

基本查询

条件查询Where

 结构体和Map查询

查询零值条件

NOT条件 

Or条件

内联条件 

额外查询选项

FirstOrInit 

 Attrs(找不到时使用)

 Assign(不管找不找到都是用)

 FirstOrCreate

 Attrs(找不到时使用)

 Assign(不管找不找到都是用)

检索相应字段

 排序

 数量

 偏移

总数 

 更新操作

保存所有字段

更新单个列

更新多列 

更新选定字段 

 更新 Hook

无Hooks更新 

 批量更新

 删除操作

基本删除 

根据主键删除 

Delete Hook

批量删除 

 阻止全局删除

软删除  

 查找被软删除的记录


创建记录

官方文档创建链接:

创建 | 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 提供了 FirstTakeLast 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 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方法,比如:CreateFirstFindTakeSaveUpdateDeleteScanRow

// 根据主键获取记录 (只适用于整形主键)
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 时不会覆盖

 更新操作

 官方中文文档:

更新 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.https://gorm.io/zh_CN/docs/update.html

保存所有字段

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;

更新选定字段 

 更新时选定、忽略某些字段,您可以使用 SelectOmit

// 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 的 BeforeUpdateAfterUpdate 方法,更新 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 - The fantastic ORM library for Golang, aims to be developer friendly.https://gorm.io/zh_CN/docs/delete.html

基本删除 

注意:删除记录时,请确保主键字段有值,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 支持 BeforeDeleteAfterDelete 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的增删查改的学习,谢谢观看!如有什么错误请各位大神在评论区指出。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
GoLang学习笔记主要包括以下几个方面: 1. 语法规则:Go语言要求按照语法规则编写代码,例如变量声明、函数定义、控制结构等。如果程序中违反了语法规则,编译器会报错。 2. 注释:Go语言中的注释有两种形式,分别是行注释和块注释。行注释使用`//`开头,块注释使用`/*`开头,`*/`结尾。注释可以提高代码的可读性。 3. 规范代码的使用:包括正确的缩进和空白、注释风格、运算符两边加空格等。同时,Go语言的代码风格推荐使用行注释进行注释整个方法和语句。 4. 常用数据结构:如数组、切片、字符串、映射(map)等。可以使用for range遍历这些数据结构。 5. 循环结构:Go语言支持常见的循环结构,如for循环、while循环等。 6. 函数:Go语言中的函数使用`func`关键字定义,可以有参数和返回值。函数可以提高代码的重用性。 7. 指针:Go语言中的指针是一种特殊的变量,它存储的是另一个变量的内存地址。指针可以实现动态内存分配和引用类型。 8. 并发编程:Go语言提供了goroutine和channel两个并发编程的基本单位,可以方便地实现多线程和高并发程序。 9. 标准库:Go语言提供了丰富的标准库,涵盖了网络编程、文件操作、加密解密等多个领域,可以帮助开发者快速实现各种功能。 10. 错误处理:Go语言中的错误处理使用`defer`和`panic`两个关键字实现,可以有效地处理程序运行过程中出现的错误。 通过以上内容的学习,可以掌握Go语言的基本语法和编程思想,为进一步学习和应用Go语言打下坚实的基础。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Golang学习笔记](https://blog.csdn.net/weixin_52310067/article/details/129467041)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [golang学习笔记](https://blog.csdn.net/qq_44336275/article/details/111143767)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值