【发布时间】:2015-03-07 01:08:28
【问题描述】:
我们使用的是 Rails 4.1,并且我们是一个带有 has_many 的模型。
Model X has_many Y
Y 可以更新,然后将通过回调更新 X(增加版本字段,modified_at 等)
X也可以自行更新。
这会导致 MySQL 内部出现死锁,因为一个事务将锁定 Y1 然后想锁定 X1,而另一个事务将锁定 X1 然后想锁定 Y1。
这很容易解决,方法是在更新 Y 之前至少要求拥有 X 的 SELECT ... FOR UPDATE。
如何在 Rails 中做到这一点?还是有更好的解决方案?
我正在考虑尝试保证我在 Y 上的 before_update 回调中有一个事务,然后在 X 上获得一个锁,但我不确定这是否适用于 Rails。
【问题讨论】:
-
我建议你避免使用回调。避免死锁的真正好方法是让每个事务以相同的顺序从表中获取行锁。在您的示例中,在更新
Y中的行之前,获取父行X1上的锁在您获取Y1上的锁之前。您仅更新X的事务将获得X1的锁定。通过以相同的顺序从表中获取锁,您可以避免大量死锁问题。为此,您几乎必须放弃 AR 回调。 -
是的,这绝对是一个解决方案,但远非最佳解决方案。我想绝对减少消除这些死锁条件所需的代码更改。我似乎成功地添加了 before_update 回调以获得所有相关的锁。
标签: mysql ruby ruby-on-rails-4 rails-activerecord