为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用 gorm 插件/钩子将新记录插入数据库

如何使用 gorm 插件/钩子将新记录插入数据库

Go
达令说 2022-07-11 16:26:17
在尝试使用 golang 中的 gorm 插入日志以检测模型的值更改时,我正在使用插件进行操作:type MyModel struct { Id Name}type Log struct { Id NewValue OldValue CreatedAt}我的插件定义是这样的:func ChangelogCreatePlugin(db *gorm.DB) {    log := &Log{NewValue: "the new value", OldValue: "the old value", CreatedAt: "current time"}    // Here is the problem    db.Save(log) <- this is not acceptable}使用插件中的参数插入不同的数据模型db *gorm.DB是不可接受的,因为该参数已初始化为接受来自触发插件的同一模型的数据。我的要求是将我的日志存储在同一个数据库事务中,因此如果其中一个失败,它们都应该失败。如何在gorm中做这样的事情?我知道钩子。钩子在我的情况下没有用,因为我希望我的日志跟踪不同的模型,所以我正在寻找更多“可重用”的解决方案,而不是在我的模型中复制/粘贴钩子实现。
查看完整描述

3 回答

?
郎朗坤

TA贡献1921条经验 获得超9个赞

经过大量的挖掘和调试,我想出了这个解决方案:


您首先需要以正确的顺序注册您的插件执行,在我的情况下应该是这样的:


gormDb.Callback().Create().Before("gorm:commit_or_rollback_transaction").Register("changelog_create", ChangelogCreatePlugin)

此命令将保证您的插件将在模型的任何插入子句的事务提交之前被激活或触发。


要了解有关在何处注册插件的更多信息,请查看在 gorm 中注册的默认回调


这样做之后,我需要调整插件代码:


func ChangelogCreatePlugin(db *gorm.DB) {

    // first make a check that the model insert transaction doesn't have any error

    if db.Error != nil {

        return

    }


    

    log := &Log{NewValue: "the new value", OldValue: "the old value", CreatedAt: "current time"}

    

    // get a new db session for the new model to work

    logDb := db.Session(&gorm.Session{})



    // if an error ocurred while saving the log

    // push it into original model db instance errors, so it will be rolledback eventually

    logErr := logDb.Save(log)

    if logErr != nil {

        db.AddError(logErr)

    }

}

希望有一天这可以帮助某人!


查看完整回答
反对 回复 2022-07-11
?
收到一只叮咚

TA贡献1821条经验 获得超4个赞

尝试创建事务性decorator女巫使用func(d *gorm.DB)或f ...func(d *gorm.DB)作为参数。它应该看起来像


type TransactionalDecorator struct {

    DB *gorm.DB

}


func (t *TransactionalDecorator) Transaction(f ...func(d *gorm.DB) error) error  {

    return t.DB.Transaction(func(tx *gorm.DB) error {

        for _, fn := range f {

            if err := fn(tx); err != nil {

                return err

            }

        }

        return nil

    })

}

所有数据库交互功能将在同一个事务中执行


repo , _ := gorm.Open(...)


tdb := &TransactionalDecorator{DB: repo}


saveModel := func(d *gorm.DB) error {

    // save model

}

saveLog := func(d *gorm.DB) error {

    // save log

}


err := tdb.Transaction(saveModel, saveLog)


查看完整回答
反对 回复 2022-07-11
?
子衿沉夜

TA贡献1828条经验 获得超3个赞

怎么样:


func ChangelogCreatePlugin(db *gorm.DB) {

    log := &Log{NewValue: "the new value", OldValue: "the old value", CreatedAt: "current time"}

    // Here is the problem

    db.Session(&gorm.Session{}).Save(log)

}

这应该给你一个“新鲜”的 db/tx 来使用


查看完整回答
反对 回复 2022-07-11
  • 3 回答
  • 0 关注
  • 179 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信