2011-09-28 58 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

相关问题