2

タスクマネージャーであるアプリケーションが1つあります。

各ユーザーは、自分に割り当てる新しいタスクを選択できます。

2人のユーザーが同時に同じタスクを受け入れる場合、同時実行の問題はありますか?

私のコードは次のようになります。

if @user.task == nil
  @task.user = @user
  @task.save
end

2人の異なるユーザーの場合、2台の異なるマシンでこのURLを同時に開きます。問題がありますか?

4

2 に答える 2

5

楽観的ロックを使用して、他の「古い」レコードがデータベースに保存されないようにすることができます。lock_versionこれを有効にするには、モデルにデフォルト値が。の列が必要です0

レコードがデータベースからフェッチされると、電流lock_versionがそれに伴います。レコードが変更されてデータベースに保存されると、データベースの行は、レコードがフェッチされたときに存在していたを制約することUPDATEにより、条件付きで更新されます。lock_version変更されていない場合は、UPDATEがインクリメントされますlock_version。変更された場合、更新は何も行わず、例外(ActiveRecord::StaleObjectError)が発生します。次のようにオフにしない限り、これはActiveRecordのデフォルトの動作です。

ActiveRecord::Base.lock_optimistically = false

(オプションで)以外の列名を使用できますlock_version。カスタム名を使用するには、モデルクラスに次のような行を追加します。

set_locking_column :some_column_name

楽観的ロックの代わりに、データベースレベルでのテーブルレベルまたは行レベルのロックに依存する悲観的ロックがあります。このメカニズムは、ロックされた行へのすべてのアクセスをブロックするため、パフォーマンスに悪影響を与える可能性があります。

于 2012-10-25T13:52:29.600 に答える
4

試したことはありませんが、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。行がロックされているため、失敗する可能性があります。ただし、ロックを取得した後、オブジェクトがデータベースから新鮮であることを確認する必要があります。これを行う別の方法がある場合があります。

EDit:リロードする必要はありwith_lockません。ソースコードをチェックして、あなたに代わって行います。 https://github.com/rails/rails/blob/4c5b73fef8a41bd2bd8435fa4b00f7c40b721650/activerecord/lib/active_record/locking/pessimistic.rb#L61

于 2012-10-25T14:01:34.570 に答える