【问题标题】:Rails how to touch Active Record Object without locking?Rails 如何在不锁定的情况下触摸 Active Record 对象?
【发布时间】:2011-11-27 02:28:48
【问题描述】:

在我的照片课中,我有这种关联。

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。

【问题讨论】:

    标签: ruby-on-rails caching locking associations touch


    【解决方案1】:

    这也是我自己偶然发现的一个问题。

    简答:解决这个问题没有简单的方法。所有touches 都包装在同一个事务中,因此出现死锁。

    长答案:我猜您需要触摸对象来使某种(依赖)缓存无效。通常推荐使用touch 仅适用于有限数量的“关系”。例如。更新评论时使文章无效。

    我的解决方案是异步收集需要失效的 DB 对象(使用 sidekiq 作业)。我为它编写了自己的控制逻辑,它定义了在对象更改时需要使哪些(其他)对象无效。例如。评论 ==> 文章。

    这样我们就有了一种更冗长的方式来使依赖对象无效。另外,我使用Model.update_all 无效,这比“触摸链”快得多。它解决了我们的死锁问题(并为我们的缓存失效增加了冗长和性能)。

    额外提示:不要使用updated_at。如果一个 DB 对象真的因为另一个对象发生了变化而发生了变化,这是非常值得商榷的。覆盖cache_key 模型可以让您轻松定义自定义缓存键,如"#{id}-#{valid_from}"valid_from 可以是您在模型上定义的时间戳(并且您使用它来代替 updated_at)。

    【讨论】:

    • 感谢您的回答。 2 年后,我不完全确定我为什么要使用触摸。使缓存无效似乎是一个很好的理由。我现在使用清扫器来使缓存条目过期。 guides.rubyonrails.org/caching_with_rails.html#sweepers。我不再在任何地方使用触摸。
    • 我喜欢valid_from的想法,但我认为您还需要将类名添加到cache_key中,例如signalvnoise.com/posts/…中的[class]/[id]-[timestamp]跨度>
    猜你喜欢
    • 2012-04-06
    • 2017-06-13
    • 1970-01-01
    • 2018-03-06
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    • 2012-07-30
    • 2023-03-19
    相关资源
    最近更新 更多