show engine innodb status 的 latest detected deadlock 区域记录最后一次死锁详情,含事务id、锁等待与持有关系、索引名及主键/二级索引值,可定位被锁行但不保存原始sql,需结合业务逻辑分析并发路径。

怎么看 SHOW ENGINE INNODB STATUS 里的死锁信息
MySQL 不会主动报出死锁的完整上下文,但每次发生死锁后,SHOW ENGINE INNODB STATUS 会在输出的 LATEST DETECTED DEADLOCK 区域记录最后一次死锁的详细过程。这个区域是唯一能直接看到「谁锁了谁、等什么、为什么卡住」的地方。
执行命令后,重点往下翻,找到以 ---TRANSACTION 开头、紧挨着 LATEST DETECTED DEADLOCK 标题的那一段。它不是日志时间戳,而是两个(或多个)事务的快照对比。
- 每个
TRANSACTION块开头会标出事务 ID(如123456789)、状态(ACTIVE或WAITING FOR THIS LOCK TO BE GRANTED)和运行时长 -
mysql tables in use和locked in InnoDB能帮你确认是否真在操作同一张表 - 关键线索在
WAITING FOR THIS LOCK TO BE GRANTED后面的lock_mode X locks rec but not gap waiting—— 这说明它在等一个行级排他锁,且是具体某条记录(不是间隙) - 往上找同个事务块里的
HELD LOCK(S),就能看到它自己持有哪些锁;再看另一个事务的WAITING和HELD,就构成死锁环
如何定位到具体哪一行被锁住了
死锁详情里不会直接写 WHERE id = 123,但会给出索引名、主键值(或二级索引值)和记录的物理位置。你需要结合 RECORD LOCKS 行来解码。
例如出现:Record lock, heap no 22 PHYSICAL RECORD: n_fields 5; compact format; info bits 0,后面跟着一串十六进制值 —— 这些就是该记录在索引页中的字段内容。其中最关键的是主键字段(如果是聚簇索引)或二级索引键值。
- 如果表有自增主键
id,通常第二字段(n_fields 5中的第 2 个)就是id的值,以十进制显示在括号里,比如0x000000000000007B→123 - 如果锁在二级索引上(比如
UNIQUE KEY email),则要看index `email` of table `test`.`users`后面的字段值,它对应的是email字段的字节序列 - 注意:如果字段是
VARCHAR,值末尾可能带填充空格或长度前缀,不能直接字符串匹配,得按实际存储格式比对
为什么有时候 SHOW ENGINE INNODB STATUS 没有死锁记录
最常见原因是:死锁刚发生完就被清掉了,而你没及时查。MySQL 只保留最后一次死锁信息,且不落盘,重启即失。另外,某些版本(如 MySQL 5.7.20+)默认关闭了死锁日志输出到错误日志的功能,只靠 SHOW 命令抓取。
- 确保没人在你之前执行过该命令 —— 每次执行都会覆盖上一次的死锁快照
- 开启
innodb_print_all_deadlocks = ON(需写入配置文件并重启),让所有死锁都记进错误日志,避免遗漏 - 注意权限:执行
SHOW ENGINE INNODB STATUS需要PROCESS权限,普通应用账号通常没有,得用 DBA 账户查 - 如果业务中死锁频发但
SHOW里为空,大概率是死锁被快速解决后又被新死锁覆盖,建议配合慢日志 + 应用层 SQL 日志交叉定位
从死锁信息反推 SQL 语句的局限性
SHOW ENGINE INNODB STATUS 不保存原始 SQL,只记录事务持有的锁和等待目标。你能知道「事务 A 持有主键=123 的 X 锁,等待主键=456 的 X 锁;事务 B 持有 456,等待 123」,但无法 100% 确定它们各自执行的是哪条 UPDATE 或 SELECT ... FOR UPDATE。
- 如果事务开了自动提交(
autocommit=1),那基本可认定每条 DML 就是一个独立事务,锁行为较单纯 - 如果事务手动控制(
BEGIN/COMMIT),就得结合应用代码看:哪几条 SQL 在同一个事务里,顺序如何,中间有没有SELECT触发隐式锁 - 特别注意
INSERT ... ON DUPLICATE KEY UPDATE和REPLACE INTO:它们会先加插入意向锁,再加唯一键冲突行的 X 锁,这种组合极易卷入死锁,但日志里只显示最终持有的锁,不体现意图
真正难的不是看懂那段输出,而是把锁行为和业务逻辑里的并发路径对上号。比如两个服务同时处理用户余额,一个走「扣减→校验」,一个走「校验→扣减」,SHOW ENGINE INNODB STATUS 只告诉你「锁住了」,但为什么选这个顺序、能不能改、改了会不会引入新问题——这些得回到代码里看。











