为啥这个事务会产生死锁?

Posted

技术标签:

【中文标题】为啥这个事务会产生死锁?【英文标题】:Why does this transaction produce a deadlock?为什么这个事务会产生死锁? 【发布时间】:2018-08-07 12:46:51 【问题描述】:

我的应用程序使用主-主 Galera 复制设置在 Maria DB 上运行。

该应用程序可以处理死锁,但我一直在努力尽量减少在填满我的日志文件时发生的死锁。仍然有一个事务经常出现死锁,我不知道如何避免它。

该过程从一个表中删除一条记录,对其他表执行一些操作,然后最后将一条记录插入到原始表中。 交易大致如下所示:

1. DELETE FROM table_a WHERE `id` = 'Foo'
2. REPLACE INTO table_b ( ... )
3. UPDATE table_c SET ....
4. INSERT INTO table_a (id,...) VALUES ('Bar',...)

尽管重试事务会修复它,但最终插入经常会出现死锁。这种模式导致死锁的原因是什么?我能做些什么来减少这种情况的发生?

【问题讨论】:

请在innodb状态监视器中查看mariadb提供的关于死锁的信息。它告诉您哪些事务的哪些语句导致死锁以及这些语句设置的锁。 我已经启用了 innodb_status_output 和 innodb_status_output_locks 虽然 log_error 中配置的文件不存在。我会看看下一个死锁发生时会发生什么 SHOW ENGINE INNODB STATUS; 是否说 INSERTINSERT 冲突? 【参考方案1】:

问题:您正在写入的节点中是否存在“死锁”?或者直到COMMIT才会出现死锁;也就是说,在尝试跨集群进行协调时?

如果在写入节点上...

尽快在事务中做

SELECT id FROM table_a WHERE ... FOR UPDATE;

表示您将在第 4 步中插入哪些行。

另外,考虑将REPLACE 更改为等效的INSERT .. ON DUPLICATE KEY UPDATE ..。我不知道它是否会直接帮助解决僵局,但至少它(可能)更有效。

如果在集群上...

您是否触摸了许多不同的行?您是否使用循环法来选择要写入哪个节点?

无论如何,加快交易速度都会有所帮助。有什么可以从交易中拉出来的。有一些想法:

规范化通常可以在它自己的事务中完成。 如果您在事务中有“如果”,那么事先进行试探性测试可能是值得的。 (但您可能需要在事务中保留“如果”。)

【讨论】:

感谢您的回复。我将尝试从应用程序中记录SHOW ENGINE INNODB STATUS。至于节点选择。是师父。每个应用程序服务器都读取和写入其自己的配对数据库节点。我会接受你关于 ON DUPLICATE KEY 的建议。谢谢你的想法。我想要效率,我会密切关注它是否会减少死锁。 我希望你只写给这对大师中的一个。 Galera 集群允许写入任何节点。 加莱拉-好的。我被“master-master”误导了。 啊是的。它称自己为多主 :) 无论如何,我使用的是 ON DUPLICATE... 而不是替换,并且会看到会发生什么。

以上是关于为啥这个事务会产生死锁?的主要内容,如果未能解决你的问题,请参考以下文章

为啥会出现死锁?

数据库事务 - 怎样才能产生 互相等待 - 死锁,怎么解决

事务 ( 进程 ID 60) 与另一个进程被死锁在锁资源上,并且已被选作死锁牺牲品。请重新运行 该事务。

如何减少SQLServer死锁发生

关于oracle数据库死锁,请大神进。为啥用java synchronized 关键字解决不了?怎么解决死锁问题?

解决一次mysql死锁问题