如何优雅的传递 tx 参数?Go 里面没有重载,这种情况有个比较通用的方案:Context。使用 Context 后续如果要做链路追踪、超时控制等也很方便扩展。
gorm 链路追踪可参考 github 上大佬的实现
我们只需要把 GetDB
改改,尝试从 ctx 中获取 tx,如果存在则不需要新建 session,直接使用传递的 tx。这个有个小技巧,使用结构体而不是字符串作为 ctx 的 key,可以保证 key 的唯一性。代码如下:
func GetDB(ctx context.Context) *gorm.DB {
iface := ctx.Value(ctxTransactionKey{})
if iface != nil {
tx, ok := iface.(*gorm.DB)
if !ok {
log.Panicf("unexpect context value type: %s", reflect.TypeOf(tx))
return nil
}
return tx
}
return globalDB.WithContext(ctx)
}
在事务上做一下 context 的封装:
func Transaction(ctx context.Context, fc func(txctx context.Context) error) error {
db := globalDB.WithContext(ctx)
return db.Transaction(func(tx *gorm.DB) error {
txctx := CtxWithTransaction(ctx, tx)
return fc(txctx)
})
}
使用事务:
ownerId := "xxx"
err := Transaction(context.Background(), func(txctx context.Context) error {
pet, err := NewPetDb(txctx).Create(&petmodel.Pet{
Name: "xxx",
Age: 1,
Sex: "female",
})
if err != nil {
return err
}
_, err = NewOwner_PetDb(txctx).Create(&petmodel.Owner_Pet{
OwnerId: ownerId,
PetId: pet.Id,
})
return err
})
Hooks & Callbacks
gorm 提供 Hooks 功能,可以在某些扩展点执行钩子函数,例如创建前生成 uuid :
func (u *Pet) BeforeCreate(tx *gorm.DB) error {
u.Id = NewUlid()
return nil
}
但是 Hooks 是针对某个 model,如果需要对所有 model,可以使用 Callbacks 。
func registerCallback(db *gorm.DB) {
// 自动添加uuid
err := db.Callback().Create().Before("gorm:create").Register("uuid", func (db *gorm.DB) {
db.Statement.SetColumn("id", NewUlid())
})
if err != nil {
log.Panicf("err: %+v", errx.WithStackOnce(err))
}
}
项目完整代码:https://github.com/win5do/go-...
本文来自:Segmentfault
感谢作者:.container .card .information strong
查看原文:在 Go 项目中优雅的使用 gorm v2
相关阅读 >>
leetcode1047 删除字符串中的所有相邻重复项 Golang
在 bigcache 中存储任意类型(interface{})
更多相关阅读请进入《Go》频道 >>

Go语言101
一个与时俱进的Go编程知识库。