2011-09-28 8 views
11

私の写真のクラスで私はこの関連があります。ロックなしでActive Record Objectに触れる方法を教えてください。

belongs_to :user, :touch => true 

私はこの例外を受け取りました。

A ActiveRecord::StatementInvalid occurred in photos#update: 

Mysql::Error: Deadlock found when trying to get lock; try restarting transaction: 
UPDATE `users` SET `updated_at` = '2011-09-20 14:17:44' WHERE `users`.`id` = 6832 
production/ruby/1.8/gems/activerecord-3.0.10/lib/active_record/connection_adapters/abstract_adapter.rb:207:in `log' 

このような将来の例外が発生しないようにするにはどうすればよいですか?可能であれば、エラーに示された更新ステートメントでロックを使用しないようにしたいと思います。オプティミスティックロックを使用することは、オプティミスティックロックがおそらくActiveRecord :: StaleObjectErrorを発生させるため、この場合には機能しないと思います。

答えて

8

私は自分自身も遭遇した問題です。

短い回答:この問題を回避する方法はありません。 touchはすべて同じトランザクションでラップされます。したがってデッドロックです。

長い答え:(依存する)キャッシュを無効にするには、オブジェクトをタッチする必要があると思います。 touchの通常推奨される使用は、限定された量の「関係」に対してのみ機能します。例えば。コメントが更新されているときに記事を無効にします。

私の解決策は、無効化する必要のあるDBオブジェクトの非同期収集(サイドキージョブを使用)でした。私は、オブジェクトが変更されたときに、(他の)オブジェクトを無効にする必要があることを定義する独自のコントロールロジックを書きました。例えば。コメント==>記事。

このようにして、従属オブジェクトを無効にする方法をもっと冗長にしました。プラス私はModel.update_allを使って無効にしましたが、それは "タッチチェーン"よりも速いです。デッドロックの問題を解決しました(キャッシュの無効化に冗長性とパフォーマンスを追加しました)。

追加チップ:updated_atを使用しないでください。別のオブジェクトが変更されたためにDBオブジェクトが実際に変更された場合、それは非常に議論の余地があります。 cache_keyモデルを上書きすると、"#{id}-#{valid_from}"のようなカスタムキャッシュキーを簡単に定義できます。 valid_fromは、モデルで定義したタイムスタンプ(updated_atの代わりに使用するタイムスタンプ)にすることができます。

+0

答えをありがとう。 2年後、私はなぜタッチを使っていたのかよくわからない。キャッシュを無効にするのは良い理由のようです。現在、掃除機を使用してキャッシュエントリを期限切れにしています。 http://guides.rubyonrails.org/caching_with_rails.html#sweepers。私はもうどこにも触れません。 –

+0

私はvalid_fromのアイデアが気に入っていますが、私はあなたがhttp://signalvnoise.com/posts/3113-にあるように[class]/[id] - [timestamp]のように、クラス名をcache_keyにも追加する必要があると思います。キーベースのキャッシュ有効期限 - 動作 – iheggie

関連する問題