我有一個應用程序是一個任務管理器。Rails 3.2 ActiveRecord併發性
每個用戶都可以選擇一個新任務分配給自己。
如果2個用戶在同一時間接受相同的任務,是否存在併發問題?
我的代碼如下所示:
if @user.task == nil
@task.user = @user
@task.save
end
如果2 diferent用戶,2臺diferent機器同時打開這個網址。我有問題嗎?
我有一個應用程序是一個任務管理器。Rails 3.2 ActiveRecord併發性
每個用戶都可以選擇一個新任務分配給自己。
如果2個用戶在同一時間接受相同的任務,是否存在併發問題?
我的代碼如下所示:
if @user.task == nil
@task.user = @user
@task.save
end
如果2 diferent用戶,2臺diferent機器同時打開這個網址。我有問題嗎?
您可以使用optimistic locking來防止其他「過時」記錄被保存到數據庫中。要啓用它,您的模型需要有lock_version
列,其默認值爲0
。
當從數據庫中提取記錄時,當前的lock_version
隨之而來。當記錄被修改並保存到數據庫時,數據庫行會有條件地更新,方法是限制lock_version
上的UPDATE
,該記錄是在提取記錄時出現的。如果它沒有改變,UPDATE
將增加lock_version
。如果更改,更新將不會執行任何操作,並且會引發異常(ActiveRecord::StaleObjectError
)。這是ActiveRecord的默認行爲,除非關閉如下:
ActiveRecord::Base.lock_optimistically = false
您可以(可選)使用比lock_version
其他列名。要使用自定義名稱,添加一行類似下面的模型類:
set_locking_column :some_column_name
樂觀鎖的替代方案是pessimistic locking,這在數據庫級別依賴於表 - 或者行級鎖。該機制將阻止對鎖定行的所有訪問,從而可能會對性能產生負面影響。
從來沒有嘗試過,但你可以使用http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html
您應該能夠獲取鎖定您的具體任務,這樣的事情:
@task = Task.find(some_id)
@task.with_lock do
#Then let's check if there's still no one assigned to this task
if @task.user.nil? && @user.task.nil?
@task.user = @user
@task.save
end
end
再次,我從來沒有使用過這個,所以我想在鎖內測試一個大的sleep
以確保它實際上鎖定了所有你想要的方式
另外我不確定reload
這裏。由於該行被鎖定,因此可能會失敗。但是在獲得鎖之後,你必須確保你的對象是來自db的新對象,可能有另一種方法來實現它。
編輯:無需重新加載,我檢查了源代碼和with_lock
是否適合你。 https://github.com/rails/rails/blob/4c5b73fef8a41bd2bd8435fa4b00f7c40b721650/activerecord/lib/active_record/locking/pessimistic.rb#L61
這個什麼:http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html我仍然不明白,但我認爲這是我需要的 –
「樂觀鎖定」(根據您的鏈接)就是上面所描述的答案。 –