Go Gorm 对增量计数器的原子更新

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

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

有没有办法使用 Gorm 原子地增加一个计数器,而不是从数据库中获取值,增加,最后更新数据库?


SMILET
浏览 268回答 2
2回答

潇湘沐

如果要使用基本的 ORM 功能,可以在检索记录时使用FOR UPDATE查询选项,数据库将锁定该特定连接的记录,直到该连接发出UPDATE查询以更改该记录。SELECT和UPDATE语句必须发生在同一个连接上,这意味着您需要将它们包装在一个事务中(否则 Go 可能会通过不同的连接发送第二个查询)。请注意,这将使所有其他想要SELECT相同记录的连接等到您完成UPDATE. 对于大多数应用程序来说,这不是问题,但如果您的并发性非常高,或者两者之间的时间SELECT ... FOR UPDATE很UPDATE长,那么这可能不适合您。除了 之外FOR UPDATE,该FOR SHARE选项听起来也可以为您工作,锁定争用较少(但我不太清楚,不能肯定地说)。注意:这假设您使用支持的 RDBMS SELECT ... FOR UPDATE; 如果没有,请更新问题以告诉我们您正在使用哪个 RDBMS。另一种选择是绕过 ORM 并执行db.Exec("UPDATE counter_table SET counter = counter + 1 WHERE id = ?", 42)

慕码人2483693

一种可能的解决方案是使用 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)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go