GORM 更新钩子实现
本文介绍 GORM 中更新操作的钩子函数实现方法。
钩子方法
BeforeUpdate
在记录更新之前执行,常用于更新前的数据校验与修改。
Go
type Product struct {
ID uint
Name string
Price float64
Stock int
UpdatedAt time.Time
}
// 更新前校验价格
func (p *Product) BeforeUpdate(tx *gorm.DB) error {
if p.Price < 0 {
return errors.New("价格不能为负数")
}
if p.Stock < 0 {
return errors.New("库存不能为负数")
}
return nil
}
BeforeUpdate 返回 error 时,更新操作会被中止并回滚事务。
AfterUpdate
在记录更新之后执行,常用于记录变更日志或触发后续操作。
Go
type Account struct {
ID uint
Balance float64
Version int
}
// 更新后记录日志
func (a *Account) AfterUpdate(tx *gorm.DB) error {
logEntry := AccountLog{
AccountID: a.ID,
Balance: a.Balance,
Action: "updated",
Time: time.Now(),
}
return tx.Create(&logEntry).Error
}
钩子方法签名
Go
// 更新前钩子
func (model *ModelName) BeforeUpdate(tx *gorm.DB) error
// 更新后钩子
func (model *ModelName) AfterUpdate(tx *gorm.DB) error
检测字段变更
Go
func (u *User) BeforeUpdate(tx *gorm.DB) error {
// 检查特定字段是否被更新
if tx.Statement.Changed("Name") {
log.Printf("用户名从 %v 改为 %v",
tx.Statement.OldValue("Name"),
tx.Statement.CurValue("Name"),
)
}
// 检查多个字段
if tx.Statement.Changed("Email", "Phone") {
log.Println("联系方式已更新")
}
return nil
}
注意事项
- Updates 和 Save 方法会触发 BeforeUpdate/AfterUpdate 钩子。
- UpdateColumn/UpdateColumns 方法不会触发任何钩子。
- 批量更新时,钩子会对每条记录分别执行。
tx.Statement.Changed("字段名")可用于检测字段是否发生变更。- BeforeUpdate 返回 error 会中止操作并回滚;AfterUpdate 的 error 不影响已提交的写入。
要点总结
- BeforeUpdate在更新前执行,适合数据校验和预处理。
- AfterUpdate在更新后执行,适合记录变更日志或触发后续操作。
- Updates/Save方法触发钩子,UpdateColumn/UpdateColumns不触发。
- 使用
tx.Statement.Changed()检测特定字段是否被更新。 - 钩子返回 error 的行为与创建钩子一致:Before 回滚,After 仅记录。
存放路径:D:\git2\jwdev\articles\GORM\进阶\钩子函数与回调机制\更新钩子实现.md
📝 发现内容有误?点击此处直接编辑