更新

1 保存所有字段

执行更新 SQL 时, Save 将保存所有字段

db.First(&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;

Save 是一个 upsert 函数:

  • 如果值不包含主键,则执行 Create

  • 如果值有主键,则首先执行 Update (所有字段,通过 Select(*) )。

  • 如果更新rows affected = 0 ,则它会自动恢复到 Create

注意Save 保证会发生更新或插入

为了防止在没有行匹配时意外创建,请使用 Select(*).Updates()

Save 方法不能与 Model 方法一起使用。如果不是模型,则需要加上where条件否则会报错 WHERE conditions required

2 阻止全局更新

如果在没有任何条件的情况下执行批量更新,GORM 将不会运行它,并且默认会返回 ErrMissingWhereClause 错误。

必须使用一些条件或使用原始 SQL 或启用 AllowGlobalUpdate 模式,例如:

3 更新单列

当使用 Update 更新单个列时,需要满足一些条件,否则会引发错误 ErrMissingWhereClause

当使用 Model 方法并且其值具有主值时,主键将用于构建条件,例如:

4 更新多列

Updates 支持使用 structmap[string]interface{} 进行更新,使用 struct 更新时默认只更新非零字段

注意: 使用结构体更新时,GORM 只会更新非零字段。你可能需要使用 map 来更新属性,或者使用 Select 来指定要更新的字段。

5 update hooks

GORM 允许使用 hooks BeforeSaveBeforeUpdateAfterSaveAfterUpdate 。这些方法会在更新记录时被调用

6 批量更新

如果我们没有使用 Model 指定具有主键值的记录,GORM 将执行批量更新

7 使用SQL表达式更新

GORM 允许使用 SQL 表达式更新列,例如:

8 从子查询更新

使用 SubQuery 更新表

9 不使用Hooks/时间跟踪

如果要跳过 Hooks 方法并且不跟踪更新时的更新时间,则可以使用 UpdateColumnUpdateColumns ,其工作原理类似于 UpdateUpdates

10 检查字段是否已改变

GORM 提供了 Changed 方法,可以在 Before Update Hooks 中使用,它将返回字段是否已更改。

Changed 方法仅适用于 UpdateUpdates 方法,并且仅检查 Update / Updates 的更新值是否等于模型值。如果已更改且未省略,则返回 true。

11 更改更新值

要更改 Before Hooks 中的更新值,应该使用 SetColumn ,除非它是使用 Save 进行的完整更新,例如:

操作​

​更新方式​

​钩子内修改字段的方法​

Save

更新所有字段

直接修改模型字段

Updates

只更新变化字段

必须使用 SetColumn

11.1 底层原理

  • GORM 在执行更新前会​​缓存变更字段​

  • BeforeUpdate钩子触发时,变更集已经确定

  • 直接修改模型字段不会更新变更集(Updates模式)

  • SetColumn会直接修改最终生成的 SQL

12 函数说明

12.1 func (db *DB) Save(value interface{}) (tx *DB)

  • 执行​​创建或全量更新​​操作:

    • 主键为零值 → 创建新记录

    • 主键非零值 → 更新​​所有字段​

12.2 func (db *DB) Update(column string, value interface{}) (tx *DB)

  • 更新​​单个字段​​,不触发钩子

  • 注意更新​​多个字段​​,支持结构体和 map,触发钩子事项:

    • 零值直接更新

    • 不支持关联更新

12.3 func (db *DB) Updates(values interface{}) (tx *DB)

  • 更新​​多个字段​​,支持结构体和 map,触发钩子

  • 注意事项

    • 结构体零值不会更新,map会更新

12.4 func (db *DB) UpdateColumn(column string, value interface{}) (tx *DB)

  • 更新单个字段,​​不触发钩子​​,​​不更新时间戳​

    • 跳过所有钩子

    • 不更新时间戳

    • 直接更新零值

12.5 func (db *DB) UpdateColumns(values interface{}) (tx *DB)

  • 批量更新字段,​​不触发钩子​​,​​不更新时间戳​

特性

Updates

UpdateColumns

钩子

触发

不触发

时间戳

更新

不更新

零值

结构体不更新

结构体不更新

性能

较低

较高

最后更新于