我有一個計算,但我的計算不是執行緒安全的,它必須使用增量或增量計數器,但我不知道如何實作它。這是我的代碼
def create
if @purchase.check_quantity(@product, purchase_params[:quantity].to_i)
return render :new
end
#calculation is not thread-safe
new_quantity = @product.quantity - purchase_params[:quantity].to_i
@purchase.assign_attributes(purchase_params)
if @purchase.save
@product.update(:quantity => new_quantity)
redirect_to product_url(@product)
else
flash[:error] = @purchase.errors.full_messages.join(', ')
render :new
end
結尾
uj5u.com熱心網友回復:
您已經注意到,您可能會遇到競爭條件,其中對您的應用程式的兩個請求幾乎同時進入該方法。兩者都 read @product.quantity,都計算new_quantity,然后你最終會得到一個將新值寫入資料庫的請求,而另一個稍慢的請求會覆寫該值。
有兩種方法可以解決這個問題。
鎖定記錄以進行更新。另一個嘗試同時更新同一記錄的行程將引發錯誤。Ruby on Rails 支持
Locking::Optimistic和Locking::Pessimistic. 這在一定程度上取決于您的特定用例,什么可能是更好的方法。另一種方法可能是在 SQL 中進行更新,以自動更新記錄。Rails 有一種方法
update_counters可以讓你計算和更新資料庫中的記錄,如下所示:Product.update_counters(@product.id, quantity: -purchase_params[:quantity].to_i)但是這種方式可能(取決于您的
check_quantity內部操作)仍然可能導致競爭條件問題,因為該方法中的檢查不會知道任何其他請求在之前立即通過檢查并在之后立即更新資料庫。
這兩種方法都可能有助于解決問題。但是選擇哪種方法取決于您的特定用例以及您需要的安全級別、用戶體驗和資料完整性。
uj5u.com熱心網友回復:
我不確定你的代碼是“不是執行緒安全的”,但我不相信你的問題是執行緒安全的。
如果您認為@purchaseor@product物件在該代碼被命中之前正在發生變化,我建議使用.reload. 如果您認為您的計算需要異步運行,您需要考慮使用ActiveJob或Sidekiq等異步作業框架。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/456272.html
標籤:轨道上的红宝石 红宝石 数据库 PostgreSQL 增量
上一篇:在Ruby中組合管道和括號的規則
