2009-05-01 17 views
4

どういうわけか、私は金曜日にこれらを手に入れます。activerecordのオプティミスティックロックは、1行につき1回しか機能しません。

私の以前の質問には、同じ問題に関するでしたが、私が可能になりまし狭いもののダウンビット:

私はそれの意味を理解しようとすると、一日これでプレーしてきました。私は、このように指定されたlock_versionのcolumとテーブル、持っている:

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

をそして私はこのような何か:私は、その最初のを確認し、第2の同オブジェクトを参照

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

- 自分の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 

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

私はRubyの男ではないんだけど、楽観的ロックは私のためによく知られているので、私はよルビー1.8.6と2.2.2アクティブなレコード

おかげで...

答えて

5

some_attribute_fieldの値がすでに「first」に等しい2回目のfirst.saveを呼び出すと、activerecordはこれを認識してdb内で更新されず、lock_versionが増分されません。 2番目の保存はdbが "最初の"と変更されていないので動作します。

2番目のテストの値を "first"以外に変更して、dbの内容と異なるようにしてください。

+0

API(gotapi.comは私が使用しているもの)で「ダーティー」と「変更」を調べることができます。 何もしないために何もしません。 – Sai

2

を使用していますそれをデバッグするのを手伝ってください。

私は2番目のセーブが実際にデータベースを更新すると考えます。両方のオブジェクトに異なるlock_versionがあり、lock_versionがUPDATEで使用されている場合、単純には不可能です(UPDATEはゼロ行を更新します)。第3の選択肢があり、

  • lock_versionは、UPDATE文で使用されるか、または
  • 両方のオブジェクトが同じlock_version実際に何とか

を得た間違って使用されていない:だから、我々は2つの方法があります。両方のsave()が独自のトランザクションにありますが、私はあなたがAUTOCOMMIT = trueを持っていると感じています

実際のSQL文を表示させることはできますか?あなたが実際に手元に照会し、何が起こっているかの意味を理解するためにはるかに簡単だろう必要があります場合は、更新ステートメントが

... WHERE JOB_ID=123 AND LOCK_VERSION=8 

のようなものをお読みください。

P.S.そしてもう一つは:あなたの例では、あなたがこのオブジェクトを持っている別のトピックでは:プロパティが時間をロードするために比較変更されていない場合

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

保存()の呼び出しは、コンテナによって無視することができます。私はActiveRecordがこの最適化を持っているかどうかわかりません。しかし、そうであれば、2番目のsave()は無視され、オプティミスティック・ロックにはチャンスがありません。

1

Vladimir氏によれば、テスト/サンプルコードには欠陥があります。属性が変更されていないため、2番目のsave!()の間に、最初はdatebaseに格納されません。次の例を参照してください:

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バージョンではあなたの例を使用すると、(古いオブジェクトの例外を除いて、それが必要として両方の時間を動作します! )

+0

私は2.2.2で同じテストを試しましたが、正しく動作します(古いオブジェクトの例外は両方とも例外です) – reto

関連する問題