登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go问答

Go Gorm 原子更新增量计数器

来源:stackoverflow

时间:2024-04-16 16:24:34 174浏览 收藏

从现在开始,我们要努力学习啦!今天我给大家带来《Go Gorm 原子更新增量计数器》,感兴趣的朋友请继续看下去吧!下文中的内容我们主要会涉及到等等知识点,如果在阅读本文过程中有遇到不清楚的地方,欢迎留言呀!我们一起讨论,一起学习!

问题内容

我有一个本质上是用户可以递增的计数器。

但是,我想避免两个用户同时递增计数器的竞争条件。

是否有一种方法可以使用 Gorm 以原子方式递增计数器,而不是从数据库中获取值、递增并最终更新数据库?


解决方案


如果您想使用基本的 orm 功能,则在检索记录时可以使用 for update 作为 query option,数据库将锁定该特定连接的记录,直到该连接发出 update 查询来更改该记录。

select 和 update 语句必须发生在同一个连接上,这意味着您需要将它们包装在事务中(否则 go 可能会通过不同的连接发送第二个查询)。

请注意,此将使所有其他想要 select 相同记录的连接等待,直到您完成 update。对于大多数应用程序来说,这不是问题,但如果您具有非常高的并发性,或者 select ... for update 和之后的 update 之间的时间很长,那么这可能不适合您。

除了 for update 之外,for share 选项听起来也可以为您工作,并且锁定争用较少(但我不太了解它,无法肯定地说这一点)。

注意:这假设您使用支持 select ... for update 的 rdbms;如果没有,请更新问题以告诉我们您正在使用哪种 rdbms。

另一种选择是绕过 orm 并执行 db.exec("update counter_table set counter = counter + 1 where id = ?", 42) (尽管请参阅 https://stackoverflow.com/a/29945125/1073170 了解一些陷阱)。

一个可能的解决方案是使用 gorm 事务(https://gorm.io/docs/transactions.html)。
err := db.Transaction(func(tx *gorm.DB) error {
        // Get model if exist
        var feature models.Feature
        if err := tx.Where("id = ?", c.Param("id")).First(&feature).Error; err != nil {
            return err
        }

        // Increment Counter
        if err := tx.Model(&feature).Update("Counter", feature.Counter+1).Error; err != nil {
            return err
        }

        return nil
    })

    if err != nil {
        c.Status(http.StatusInternalServerError)
        return
    }

    c.Status(http.StatusOK)

今天关于《Go Gorm 原子更新增量计数器》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!

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