<p>死锁信息只出现在SHOW ENGINE INNODB STATUS结果的LATEST DETECTED DEADLOCK小节,它是最近一次死锁的完整快照,以 (1) TRANSACTION和 (2) TRANSACTION开头,包含持锁与等待锁关系、索引名、锁类型及SQL线索,需立即执行命令捕获以防被新死锁覆盖。</p>

SHOW ENGINE INNODB STATUS 输出里哪部分才是死锁信息
死锁信息只出现在 SHOW ENGINE INNODB STATUS 结果的 LATEST DETECTED DEADLOCK 小节,不是开头的 TRANSACTIONS 或中间的 SEMAPHORES。这个小节默认只保留最近一次死锁记录,且仅在真正发生死锁后才生成——没触发过死锁,这部分就为空。
执行命令后,用 Ctrl+F 搜索 LATEST DETECTED DEADLOCK 快速定位。它上面可能有时间戳(如 *** (1) TRANSACTION:),下面紧跟着两个事务的详细堆栈。
- 每个事务块以
*** (1) TRANSACTION:或*** (2) TRANSACTION:开头 - 关键字段包括:
mysql tables in use(涉及表)、locked by(持有锁的事务)、lock mode(锁类型,如X locks rec but not gap)、waiting for this lock to be granted(等待的锁) - 注意看
WAITING FOR和HOLDS THE LOCK(S)的对应关系,这是判断循环等待的核心
如何从死锁日志还原 SQL 执行顺序
死锁日志不直接显示原始 SQL,但会给出线程 ID、事务 ID、表名、索引名和记录主键值(如 0: len 4; hex 8000000a; asc ;; 对应十进制 10)。你需要结合 SHOW PROCESSLIST 或错误日志里的线程 ID,查出当时执行的语句。
-
TRANSACTION行后的mysql thread id可用于关联SHOW PROCESSLIST中的ID - 如果应用开启了 general_log 或 slow_log,可按时间戳+线程 ID 去查原始 SQL
- 主键值需手动转义:十六进制
8000000a是带符号 int,取后 4 字节 → 0x0000000a = 10;如果是字符串主键,看asc后面的可读字符 - 索引名(如
PRIMARY或idx_name)提示了 WHERE 条件走哪个索引,反推查询条件范围
为什么 SHOW ENGINE INNODB STATUS 看不到死锁,但应用报错 Deadlock found
常见原因是死锁被自动回滚后,LATEST DETECTED DEADLOCK 小节被后续另一次死锁覆盖,或该死锁发生在你执行 SHOW ENGINE INNODB STATUS 之前。InnoDB 不保留历史死锁记录。
- 死锁检测是瞬时事件,必须在发生后立刻执行命令才能捕获
- 高并发场景下,两次执行间隔内可能已发生并清理多个死锁
- 确认是否启用了
innodb_print_all_deadlocks=ON:设为 ON 后,所有死锁都会写入 MySQL 错误日志(mysqld.log),不受覆盖限制 - 检查错误日志路径:
SHOW VARIABLES LIKE 'log_error';,然后 grep “Deadlock”
死锁日志里常见的误导信息和排查盲区
别只盯着 WAITING FOR 行——真正的问题常藏在 HOLDS THE LOCK(S) 的事务做了什么。比如事务 A 等 B 的锁,但 B 其实正等着 A 释放另一把锁,而日志里可能只显示 B 在等“某条记录”,没说那条记录是 A 刚插入还没提交的。
-
lock mode S(共享锁)通常不会直接导致死锁,但和X(排他锁)组合时可能形成等待链 -
gap before rec或insert intention表示间隙锁冲突,多见于 INSERT … SELECT 或唯一键重复插入场景 - 如果看到
TABLE LOCK而不是RECORD LOCKS,说明是 metadata lock(如 ALTER TABLE 未完成),这类锁不在 InnoDB 层,SHOW ENGINE INNODB STATUS不显示细节 - 应用层重试逻辑可能掩盖真实频率:一次死锁被重试掩盖,实际每分钟发生多次,需查错误日志频次而非单次日志
死锁分析不能只靠一次输出——要连续抓日志、比对线程状态、还原业务操作序列。最麻烦的不是看不懂日志,而是日志里根本没体现应用层事务边界的划分方式。


















