使用 closure_tree 时如何避免数据库死锁?在层次结构上同时操作一组具有共同属性的模型?
它们有以下几种口味:
发出#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)
with_advisory_lock看起来很有前途。有什么想法吗?
最佳答案
作者 closure_tree这里:
先生。 Heal 的建议通常是正确的——您应该以相同的顺序获取表锁以防止死锁。不过,在这种情况下,死锁是由层次结构表中的行级锁引起的。
有趣的是你建议使用 with_advisory_lock !我刚刚为 closure_tree 编写了该库,如果您使用的版本 >= 3.7.0,则已经有保护类级 #rebuild
和 #find_or_create_by_path
的咨询锁方法。
建议锁(至少对于 MySQL 和 PostgreSQL)的问题是它们不遵守事务边界——如果持有锁的调用者在锁释放之前没有提交他们的事务,其他连接将看不到那些当他们尝试获取咨询锁时会发生变化,所以我们在这里需要小心。我们可能需要在层次结构表上为任何写入添加表锁,但这是最坏的情况。
我打开了issue 41 ,我们可以在那里追踪它。首先要做的是在并行测试中可靠地重现死锁。我们已经对 #rebuild
和 #find_or_create_by_path
进行了测试。
关于mysql - 并发编辑闭包树层次结构时出现死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14753906/