2015-10-27 25 views
2

我們有一個elements的表格,可以是issued給客戶。這些elements只能給客戶一次,而且我們有很多客戶可能會同時提取所有元素的情況。然後我們需要返回與它相關的數據(所以有更新,然後選擇)。在處理競態條件時選擇並更新一行?

目前的解決方案是一個隨機發現/更新爲issued=true設置其id作爲LAST_INSERTED_ID;然後立即使選擇呼叫找到where('id = LAST_INSERTED_ID()'),每個連接都是唯一的。

由於我們正在更新issued=falseissued=true and [last inserted]的位置,因此,一個呼叫足夠小,不會遇到競態條件問題。

但是,所有這些都是在SQL中完成,感覺非常黑客。這似乎並不是一個足夠罕見的問題,它還沒有使用更多的Railsy解決方案解決。包裝事務可能會阻止雙重問題,但在事務失敗的情況下,我們需要重試邏輯。

我們沒有想到什麼解決方案?

+0

我沒有一噸的經驗在這裏,這是對我有意思。你是否在一個數據庫查詢中查找並更新'issued = true'?你怎麼做到的? –

+0

請問您可以發表您的問題 –

回答

0

您將希望使用數據庫級鎖定來避免競爭條件。在MySQL中做到這一點

一種方法是SELECT FOR UPDATE這樣的:

SELECT * FROM elements WHERE issued=false LIMIT 1 FOR UPDATE

在ActiveRecord的(滑軌),這就是所謂的pessimistic locking,和實施應該是這樣的:

Element.transaction do 
    element = Element.lock(true).where(issued: false).first 
    element.issued = true 
    # ... do other stuff to assign to a given client 
    element.save! 
end 

如果同時啓動多次,第二次調用將被阻塞,直到第一次調用完成,所以在執行第一次調用時,第一個記錄已經更新爲= true和th第二次調用將返回下一條記錄而不是相同的記錄。

你可以閱讀有關SELECT FOR UPDATEhere