2011-09-28 60 views
11

在我的照片班中,我有這種關聯。Rails如何在不鎖定的情況下觸摸活動記錄對象?

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 es被包裝在同一個事務中,因此是死鎖。

長答案:我猜你需要觸摸對象來使某種(從屬)緩存無效。通常推薦使用touch僅適用於有限數量的「關係」。例如。評論正在更新時使文章無效。

我的解決方案是需要失效的DB對象的異步集合(使用sidekiq作業)。我爲它定義了自己的控制邏輯,它定義了當對象發生變化時,(其他)對象需要失效。例如。評論==>文章。

這樣我們有一種更冗長的方式使依賴對象無效。另外我使用Model.update_all無效,這比「觸摸鏈」快得多。它解決了我們的死鎖問題(並且爲我們的緩存失效添加了冗長和性能)。

額外貼士:請勿使用updated_at。如果因爲另一個對象改變而導致數據庫對象真的發生了變化,這是非常有爭議的。覆蓋cache_key模型可讓您輕鬆定義像"#{id}-#{valid_from}"這樣的自定義緩存鍵。 valid_from可能是您在模型上定義的時間戳(並且您使用的是而不是updated_at)。

+0

感謝您的回答。這是2年後,我不完全確定我爲什麼使用觸摸。使緩存失效似乎是一個很好的理由。我現在使用清理器過期緩存條目。 http://guides.rubyonrails.org/caching_with_rails.html#sweepers。我不再使用觸摸了。 –

+0

我喜歡valid_from的想法,但我認爲你需要在cache_key中添加類名,例如[class]/[id] - [timestamp]按照http://signalvnoise.com/posts/3113-如何琴鍵基於緩存過期,作品 – iheggie

相關問題