亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Go Gorm 對增量計數器的原子更新

Go Gorm 對增量計數器的原子更新

Go
SMILET 2022-06-01 15:21:49
我有一個本質上是用戶可以增加的計數器。但是,我想避免兩個用戶同時增加計數器的競爭條件。有沒有辦法使用 Gorm 原子地增加一個計數器,而不是從數據庫中獲取值,增加,最后更新數據庫?
查看完整描述

2 回答

?
瀟湘沐

TA貢獻1816條經驗 獲得超6個贊

如果要使用基本的 ORM 功能,可以在檢索記錄時使用FOR UPDATE查詢選項,數據庫將鎖定該特定連接的記錄,直到該連接發出UPDATE查詢以更改該記錄。

SELECTUPDATE語句必須發生在同一個連接上,這意味著您需要將它們包裝在一個事務中(否則 Go 可能會通過不同的連接發送第二個查詢)。

請注意,這將使所有其他想要SELECT相同記錄的連接等到您完成UPDATE. 對于大多數應用程序來說,這不是問題,但如果您的并發性非常高,或者兩者之間的時間SELECT ... FOR UPDATEUPDATE長,那么這可能不適合您。

除了 之外FOR UPDATE,該FOR SHARE選項聽起來也可以為您工作,鎖定爭用較少(但我不太清楚,不能肯定地說)。

注意:這假設您使用支持的 RDBMS SELECT ... FOR UPDATE; 如果沒有,請更新問題以告訴我們您正在使用哪個 RDBMS。

另一種選擇是繞過 ORM 并執行db.Exec("UPDATE counter_table SET counter = counter + 1 WHERE id = ?", 42)


查看完整回答
反對 回復 2022-06-01
?
慕碼人2483693

TA貢獻1860條經驗 獲得超9個贊

一種可能的解決方案是使用 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)


查看完整回答
反對 回復 2022-06-01
  • 2 回答
  • 0 關注
  • 241 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號