删除一条记录

删除一条记录时,删除对象需要指定主键,否则会触发 批量删除,例如:

  1. // Email 的 ID 是 `10`
  2. db.Delete(&email)
  3. // DELETE from emails where id = 10;
  4. // 带额外条件的删除
  5. db.Where("name = ?", "jinzhu").Delete(&email)
  6. // DELETE from emails where id = 10 AND name = "jinzhu";

根据主键删除

GORM 允许通过主键(可以是复合主键)和内联条件来删除对象,它可以使用数字(如以下例子。也可以使用字符串——译者注)。查看 查询-内联条件(Query Inline Conditions) 了解详情。

  1. db.Delete(&User{}, 10)
  2. // DELETE FROM users WHERE id = 10;
  3. db.Delete(&User{}, "10")
  4. // DELETE FROM users WHERE id = 10;
  5. db.Delete(&users, []int{1,2,3})
  6. // DELETE FROM users WHERE id IN (1,2,3);

钩子函数

对于删除操作,GORM 支持 BeforeDeleteAfterDelete Hook,在删除记录时会调用这些方法,查看 Hook 获取详情

  1. func (u *User) BeforeDelete(tx *gorm.DB) (err error) {
  2. if u.Role == "admin" {
  3. return errors.New("admin user not allowed to delete")
  4. }
  5. return
  6. }

批量删除

如果指定的值不包括主属性,那么 GORM 会执行批量删除,它将删除所有匹配的记录

  1. db.Where("email LIKE ?", "%jinzhu%").Delete(&Email{})
  2. // DELETE from emails where email LIKE "%jinzhu%";
  3. db.Delete(&Email{}, "email LIKE ?", "%jinzhu%")
  4. // DELETE from emails where email LIKE "%jinzhu%";

可以将一个主键切片传递给Delete 方法,以便更高效的删除数据量大的记录

  1. var users = []User{{ID: 1}, {ID: 2}, {ID: 3}}
  2. db.Delete(&users)
  3. // DELETE FROM users WHERE id IN (1,2,3);
  4. db.Delete(&users, "name LIKE ?", "%jinzhu%")
  5. // DELETE FROM users WHERE name LIKE "%jinzhu%" AND id IN (1,2,3);

阻止全局删除

当你试图执行不带任何条件的批量删除时,GORM将不会运行并返回ErrMissingWhereClause 错误

如果一定要这么做,你必须添加一些条件,或者使用原生SQL,或者开启AllowGlobalUpdate 模式,如下例:

  1. db.Delete(&User{}).Error // gorm.ErrMissingWhereClause
  2. db.Delete(&[]User{{Name: "jinzhu1"}, {Name: "jinzhu2"}}).Error // gorm.ErrMissingWhereClause
  3. db.Where("1 = 1").Delete(&User{})
  4. // DELETE FROM `users` WHERE 1=1
  5. db.Exec("DELETE FROM users")
  6. // DELETE FROM users
  7. db.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{})
  8. // DELETE FROM users

返回删除行的数据

返回被删除的数据,仅当数据库支持回写功能时才能正常运行,如下例:

  1. // 回写所有的列
  2. var users []User
  3. DB.Clauses(clause.Returning{}).Where("role = ?", "admin").Delete(&users)
  4. // DELETE FROM `users` WHERE role = "admin" RETURNING *
  5. // users => []User{{ID: 1, Name: "jinzhu", Role: "admin", Salary: 100}, {ID: 2, Name: "jinzhu.2", Role: "admin", Salary: 1000}}
  6. // 回写指定的列
  7. DB.Clauses(clause.Returning{Columns: []clause.Column{{Name: "name"}, {Name: "salary"}}}).Where("role = ?", "admin").Delete(&users)
  8. // DELETE FROM `users` WHERE role = "admin" RETURNING `name`, `salary`
  9. // users => []User{{ID: 0, Name: "jinzhu", Role: "", Salary: 100}, {ID: 0, Name: "jinzhu.2", Role: "", Salary: 1000}}

软删除

如果你的模型包含了 gorm.DeletedAt字段(该字段也被包含在gorm.Model中),那么该模型将会自动获得软删除的能力!

当调用Delete时,GORM并不会从数据库中删除该记录,而是将该记录的DeleteAt设置为当前时间,而后的一般查询方法将无法查找到此条记录。

  1. // user's ID is `111`
  2. db.Delete(&user)
  3. // UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
  4. // Batch Delete
  5. db.Where("age = ?", 20).Delete(&User{})
  6. // UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
  7. // Soft deleted records will be ignored when querying
  8. db.Where("age = 20").Find(&user)
  9. // SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;

如果你并不想嵌套gorm.Model,你也可以像下方例子那样开启软删除特性:

  1. type User struct {
  2. ID int
  3. Deleted gorm.DeletedAt
  4. Name string
  5. }

查找被软删除的记录

你可以使用Unscoped来查询到被软删除的记录

  1. db.Unscoped().Where("age = 20").Find(&users)
  2. // SELECT * FROM users WHERE age = 20;

永久删除

你可以使用 Unscoped来永久删除匹配的记录

  1. db.Unscoped().Delete(&order)
  2. // DELETE FROM orders WHERE id=10;

删除标志

默认情况下,gorm.Model使用*time.Time作为DeletedAt 的字段类型,不过软删除插件gorm.io/plugin/soft_delete同时也提供其他的数据格式支持

提示 当使用DeletedAt创建唯一复合索引时,你必须使用其他的数据类型,例如通过gorm.io/plugin/soft_delete插件将字段类型定义为unix时间戳等等

  1. import gorm.io/plugin/soft_delete

type User struct { ID uint Name string gorm:"uniqueIndex:udx_name" DeletedAt soft_delete.DeletedAt gorm:"uniqueIndex:udx_name" }

Unix 时间戳

使用unix时间戳作为删除标志

  1. import "gorm.io/plugin/soft_delete"
  2. type User struct {
  3. ID uint
  4. Name string
  5. DeletedAt soft_delete.DeletedAt
  6. }
  7. // 查询
  8. SELECT * FROM users WHERE deleted_at = 0;
  9. // 软删除
  10. UPDATE users SET deleted_at = /* current unix second */ WHERE ID = 1;

你同样可以指定使用毫秒 milli或纳秒 nano作为值,如下例:

  1. type User struct {
  2. ID uint
  3. Name string
  4. DeletedAt soft_delete.DeletedAt `gorm:"softDelete:milli"`
  5. // DeletedAt soft_delete.DeletedAt `gorm:"softDelete:nano"`
  6. }
  7. // 查询
  8. SELECT * FROM users WHERE deleted_at = 0;
  9. // 软删除
  10. UPDATE users SET deleted_at = /* current unix milli second or nano second */ WHERE ID = 1;

使用 1 / 0 作为 删除标志

  1. import "gorm.io/plugin/soft_delete"
  2. type User struct {
  3. ID uint
  4. Name string
  5. IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"`
  6. }
  7. // 查询
  8. SELECT * FROM users WHERE is_del = 0;
  9. // 软删除
  10. UPDATE users SET is_del = 1 WHERE ID = 1;

混合模式

混合模式可以使用 01或者unix时间戳来标记数据是否被软删除,并同时可以保存被删除时间

  1. type User struct {
  2. ID uint
  3. Name string
  4. DeletedAt time.Time
  5. IsDel soft_delete.DeletedAt `gorm:"softDelete:flag,DeletedAtField:DeletedAt"` // use `1` `0`
  6. // IsDel soft_delete.DeletedAt `gorm:"softDelete:,DeletedAtField:DeletedAt"` // use `unix second`
  7. // IsDel soft_delete.DeletedAt `gorm:"softDelete:nano,DeletedAtField:DeletedAt"` // use `unix nano second`
  8. }
  9. // 查询
  10. SELECT * FROM users WHERE is_del = 0;
  11. // 软删除
  12. UPDATE users SET is_del = 1, deleted_at = /* current unix second */ WHERE ID = 1;