登录
首页 >  Golang >  Go问答

使用 gorm 插件/钩子实现数据库中新增记录

来源:stackoverflow

时间:2024-03-08 13:36:25 186浏览 收藏

IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《使用 gorm 插件/钩子实现数据库中新增记录》,聊聊,我们一起来看看吧!

问题内容

在尝试使用 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 中做这样的事情?

我知道挂钩。挂钩在我的情况下没有用,因为我希望我的日志跟踪不同的模型,因此我正在寻找更多“可重用”的解决方案,而不是在模型中复制/粘贴挂钩实现。


解决方案


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

您首先需要以正确的顺序注册插件执行,在我的例子中,它应该是这样的:

gormdb.callback().create().before("gorm:commit_or_rollback_transaction").register("changelog_create", changelogcreateplugin)

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

要详细了解在哪里可以注册插件,请查看 the default callbacks registered in 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)
    }
}

希望有一天这会对某人有所帮助!

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

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)

到这里,我们也就讲完了《使用 gorm 插件/钩子实现数据库中新增记录》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于的知识点!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>