当使用树并发操作层次结构上具有公共属性的一组模型时,如何避免数据库死锁?
它们有以下几种味道:
发出一个#append/prepend_sibling时的
Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction:
UPDATE `elements` SET `sort_order` = `sort_order` + 1 WHERE (`parent_id` = 28035 AND `sort_order` >= 1)
Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction:
UPDATE `elements` SET `sort_order` = `sort_order` - 1 WHERE (`parent_id` = 21168 AND `sort_order` <= -1)在重新生成闭包表时
Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction:
DELETE FROM `element_hierarchies`
WHERE descendant_id IN (
SELECT DISTINCT descendant_id
FROM ( SELECT descendant_id
FROM `element_hierarchies`
WHERE ancestor_id = 16332
) AS x )
OR descendant_id = 16332
Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction:
INSERT INTO `element_hierarchies` (`ancestor_id`, `descendant_id`, `generations`) VALUES (30910, 30910, 0)锁定看起来很有前途。有什么想法吗?
发布于 2013-02-10 18:09:22
这里是树的作者:
Heal先生的建议通常是正确的--您应该按照相同的顺序获得表锁,以防止死锁。但是,在这种情况下,死锁是由于层次结构表中的行级锁造成的。
有趣的是,您建议使用锁定!我刚刚为closure_tree编写了这个库,如果您使用的是>= 3.7.0版本,那么已经有了保护类级#rebuild和#find_or_create_by_path方法的建议锁。
咨询锁的问题(至少对于MySQL和PostgreSQL)是,它们不尊重事务边界--如果持有锁的调用方在释放锁之前没有提交事务,其他连接在试图获取咨询锁时不会看到这些更改,因此我们需要在这里小心。我们可能需要为任何写操作在层次结构表上添加一个表锁,但这将是最坏的情况。
我打开了问题41,我们可以在那里追踪它。首先要做的是在并行测试中可靠地再现死锁。我们已经有针对#rebuild和#find_or_create_by_path的测试了。
发布于 2013-02-07 15:19:04
您需要考虑一个事务如何与另一个事务一起工作。最好的办法是确保先读取内容(选择),然后再写SQL。还要确保写SQL以相同的顺序使用表-即在这两种情况下都写入表A然后B。这将防止在另一个事务持有时需要锁,而另一个事务需要另一个事务锁。
或者,您可以检测死锁并采取适当的操作。我建议从一开始就避开它们。
https://stackoverflow.com/questions/14753906
复制相似问题