2

私は次の関係を持っています

parent has_many children 
child  belongs_to parent

そして次のコードブロック

ActiveRecord::Base.connection.transaction do
  lock_acquired = true
  if child.parent.lock! and child.parent.status == 1
    child.parent.update_attributes(:status => 2)
  else
    lock_acquired = false
  end

  if lock_acquired
   # other code follows here
  end

end

上記のコード ブロックは、一度に 1 つの子のみが親のステータスを変更できるようにするためのものであり、したがってロックされます。メソッドとステータス チェック式。でもなぜか壊れてます。子の 1 人によって親ステータスが 2 に変更されても、別の子は if ステートメントを何とか通過できます。もちろん、複数のプロセスが実行されていますが、ロックがそれを処理すると思いました。トランザクション ブロックが完了する前にロックが返されたようです。

ロックの動作が思ったより違うかもしれません。どんな洞察も非常に役に立ちます。

ありがとう。

4

1 に答える 1

1

更新されたコードが機能しない理由はよくわかりませんが、奇妙な点が 1 つありlock!ます。true/false 値を返すかのように使用していますが、モデル インスタンス自体しか返すことができません (ロックが取得された場合) またはエラーが発生します (ロックの取得がタイムアウトした場合)。これは、ロックが実際取得されたが、親のステータスが に等しくない場合lock_acquiredにのみ が設定されることを意味します。false1

このコードは、より予測どおりに動作する可能性があります。

child.parent.with_lock do
  if child.parent.status == 1
    child.parent.update_attributes(:status => 2)
  end

  # other code follows here
end

with_lockと同様に動作することに注意してくださいlock!-- ブロックが実行されるか、ロック タイムアウト エラーがスローされます (デフォルトの MySQL 設定で 50 秒待機した後)。

于 2013-08-20T19:27:53.273 に答える