gorm实现MySQL的INSERT INTO ... ON DUPLICATE KEY UPDATE差异化插入和更新
比如插入 f_create_uid,更新时忽略 f_create_uid,只更新 f_update_uid。可使用 gorm 的 BeforeCreate 和 BeforeUpdate 钩子,这两个钩子分别在创建和更新记录之前被调用。
// BeforeCreate 在创建记录之前调用
func (dob *MyStruct) BeforeCreate(tx *gorm.DB) (err error) {
dob.CreateUid = // 设置创建人id
dob.UpdateUid = // 设置更新人id
// 使用 dob 值更新:
//tx.Statement.SetColumn("f_create_uid", dob.CreateUid) // 钩子中被调用,第三个参数不需要指定为 true
return
}
// BeforeUpdate 在更新记录之前调用
func (dob *MyStruct) BeforeUpdate(tx *gorm.DB) (err error) {
dob.UpdateUid = // 设置更新人id
return
}
注册和应用钩子:
// 注册钩子
db.Callback().Create().Before("gorm:create").Register("before_create", func(db *gorm.DB) {
if dob, ok := db.Statement.Dest.(MyStruct); ok {
dob.BeforeCreate(db)
}
})
db.Callback().Update().Before("gorm:update").Register("before_update", func(db *gorm.DB) {
if dob, ok := db.Statement.Dest.(MyStruct); ok {
dob.BeforeUpdate(db)
}
})
// 批量插入或更新(在冲突时更新除主键以外的所有列到新值)
db := tx.Model(&MyStruct{})
db = db.Omit("f_id", "f_update_time", "f_create_time", "f_memo")
db = db.Clauses(clause.OnConflict{UpdateAll: true})
err := db.Create(me).Error
if err != nil {
fmt.Printf("InsertOrUpdate error: %s", err.Error())
return nil, err
}
取消注册的钩子:
// 取消注册 BeforeCreate 钩子
db.Callback().Create().Before("gorm:create").Unregister("before_create")
// 取消注册 BeforeUpdate 钩子
db.Callback().Update().Before("gorm:update").Unregister("before_update")
示例:
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type User struct {
Id int
Name string
}
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
fmt.Printf("name: %s\n", u.Name)
tx.Statement.SetColumn("name", u.Name)
return
}
//func (u *User) BeforeSave(tx *gorm.DB) (err error) {
// u.Name = "Sally"
// return
//}
func main() {
dsn := "user:password@tcp(host:port)/dbname?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// 注册 BeforeCreate 钩子
db.Callback().Create().Before("gorm:create").Register("before_create", func(db *gorm.DB) {
if user, ok := db.Statement.Dest.(*User); ok {
user.BeforeCreate(db)
}
})
// 注册 BeforeSave 钩子
//db.Callback().Save().Before("gorm:save").Register("before_save", func(db *gorm.DB) {
// if user, ok := db.Statement.Dest.(*User); ok {
// user.BeforeSave(db)
// }
//})
db.AutoMigrate(&User{})
user := User{
Name: "Blake",
}
err = db.Create(&user).Error
if err != nil {
panic(err)
}
fmt.Println(user.Name)
}
分类:
go
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义