質問

どういうわけか、私は常に金曜日にこれらを取得します。

以前の質問は同じ問題に関するものでしたが、今では少し絞り込むことができます:

私は一日中、これを理解しようとしてずっと遊んでいます。次のように指定されたlock_versionカラムを持つテーブルがあります:

add_column :jobs, :lock_version, :integer, :default=>0

そして、私はこのようなことをします:

foo = job.create!
first = Job.find(foo.id)
second = Job.find(foo.id)

次に、1番目と2番目が同じオブジェクトを参照していることを確認します-それらのIDは同じであり、mysqlコマンドラインツールを使用してデータベース内のその行を確認します。

first.some_attribute_field = 'first'
second.some_attribute_field = 'second'
first.save
second.save

これまでのところ問題ありません。 ActiveRecord :: StaleObjectError例外を正しく受け取ります。 ただし

first = Job.find(foo.id)
second = Job.find(foo.id)
first.some_attribute_field = 'first'
second.some_attribute_field = 'second'
first.save
second.save

...そして何も起こりません。私が正しい(スローされた例外)動作を得るのは、最初と2番目のlock_versionが0であるときだけです。最初の保存の後、再び0になることはありません。これは一体どういうことですか?

Ruby 1.8.6とアクティブレコード2.2.2を使用しています

ありがとう...

役に立ちましたか?

解決

some_attribute_fieldの値が既に「first」に等しい2回目にfirst.saveを呼び出すと、activerecordはこれを認識しているため、lock_versionがインクリメントされないようにdbを更新しません。データベースは" first"で変更されなかったため、2番目の保存は機能します。

2番目のテストの値を「最初」以外の値に変更してみてください。データベースにあるものと異なるように。

他のヒント

私はRubyの男ではありませんが、楽観的なロックはよく知っているので、デバッグを支援します。

2回目の保存で実際にデータベースが更新されると思います。両方のオブジェクトのlock_versionが異なり、lock_versionがUPDATEで使用されている場合、それは不可能です(UPDATEはゼロ行を更新します)。そのため、2つの選択肢しかありません:

  • lock_versionはUPDATEステートメントで使用されていないか、誤って使用されています
  • 両方のオブジェクトが何らかの形で同じlock_versionを取得しました

実際には、3番目の選択肢があります:save()は両方とも独自のトランザクションにありますが、AUTOCOMMIT = true を持っていると感じています)

実際のSQLステートメントを表示できますか?更新ステートメントは次のようになります

... WHERE JOB_ID=123 AND LOCK_VERSION=8

実際のクエリを手元に置いておくと、何が起こっているのかを理解しやすくなります。

PSそしてもう1つ:別のトピックの例では、次のオブジェクトがあります。

#<Job id: 323, lock: 8, worker_host: "second">

プロパティがロード時間と比較して変更されない場合、コンテナはsave()呼び出しを無視することがあります。 ActiveRecordにこの最適化があるかどうかはわかりませんが。しかし、もしそうなら、2番目のsave()は無視され、楽観的ロックは作動する機会がありません。

ウラジミールが言ったように、テスト/サンプルコードには少し欠陥があります。最初の属性は変更されていないため、2番目のsave!()の間はデータベースに保存されません。次の例を参照してください。

foo = Account.create!

first = Account.find(foo.id)
first.cash = 100
first.save!


first = Account.find(foo.id)
first.cash = 100

puts "First lock before " + first.lock_version.to_s
first.save!
puts "First lock after " + first.lock_version.to_s

これは以下を生成します:

% script/runner another_tester.rb                               
First lock before 1
First lock after 1

2.3.2バージョンのrailsで例を使用すると、2番目が保存されたときにStaleオブジェクト例外が発生するはずです(両方とも!)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top