InnoDB 死锁是 INSERT/UPDATE/DELETE 独有的吗?

700*_*are 8 mysql innodb deadlock

我正在解决 MySQL 错误“尝试获取锁定时发现死锁;尝试重新启动事务”

我将不得不更新程序以允许死锁。该SELECT语句是否可能会产生死锁错误?我知道它只是一个读锁,所以多重选择不会有问题,但是如果有一个INSERT, UPDATEorDELETE语句(可能有连接的子查询)和一个SELECT语句(可能有连接或子查询)怎么办?

是否有可能在SELECT而不是INSERT,UPDATE或上抛出错误DELETE

如果你好奇,故事就在这里。

Rol*_*DBA 5

您问题标题的直接答案是否定的。

SELECT 查询可以在gen_clust_index上执行锁定,也就是聚集索引。

以下是我与提出这些问题的人@RedBlueThing一起积极查看的三个 DBA Stack Exchanges问题。@RedBlueThing 为他的问题找到了解决方法。

只是为了让您的问题保持正确,当您查看这些答案时(不要看得太深,即使我看着自己令人费解的答案也会头晕目眩),应该很快就会发现 SELECT 查询可以锁定数据。

您还有 SELECT 的特殊情况,您可以在其中按需锁定特定行

更新 2011-08-08 16:49 EDT

您问了变体问题:“SELECT 是否可能会抛出 InnoDB 死锁异常” 在特定条件下,答案可以是 Yes。那条件是什么?如果由于错误而仅回滚单个 SQL 语句,则可能会保留该语句设置的某些锁。发生这种情况是因为 InnoDB 以一种格式存储行锁,以至于它之后无法知道哪个语句设置了哪个锁

根据该陈述,导致这种情况的事件序列理论上可能如下:

  • 您的 SQL 更新单行但生成错误
  • UPDATE 导致一行回滚
  • 该行有一个挥之不去的锁定

就个人而言,最后一句话让我感到害怕。如果 MySQL 能够将这个怪癖告知每个人,那就太好了。然而,该声明来自 MySQL 文档。(哦,是的,Oracle 拥有 InnoDB)

更新 2015-09-22 18:40 美国东部时间

今年早些时候,我了解到Percona 有一个很酷的 Nagios 检查,可以找到这些隐藏在睡眠连接后面的讨厌的锁。您现在要做的就是从该链接运行代码:

SELECT COALESCE(MAX(IF(p.command = 'Sleep', p.time, 0)), 0) AS idle_in_trx
FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS AS w
INNER JOIN INFORMATION_SCHEMA.INNODB_TRX        AS b ON  b.trx_id = w.blocking_trx_id
INNER JOIN INFORMATION_SCHEMA.INNODB_TRX        AS r ON  r.trx_id = w.requesting_trx_id
LEFT JOIN  INFORMATION_SCHEMA.PROCESSLIST       AS p ON  p.id     = b.trx_mysql_thread_id;
Run Code Online (Sandbox Code Playgroud)

这仅适用于 MySQL 5.5+。如果您有 MySQL 5.1 或更低版本,则必须终止所有休眠连接以释放锁。