直接查看SHOW ENGINE INNODB STATUS\G中的LATEST DETECTED DEADLOCK区块即可精准定位死锁,它完整呈现两个事务的SQL、线程ID、持锁与等待锁关系、索引名及锁类型,比错误日志更全更及时;重点分析(1)(2)事务块中的HOLDS THE LOCK(S)和WAITING FOR THIS LOCK TO BE GRANTED,对照锁对象可还原循环等待环。

直接看 SHOW ENGINE INNODB STATUS\G 里的 LATEST DETECTED DEADLOCK 段,它比错误日志更全、更及时——错误日志只记被回滚的事务,而这里能看到两个事务的完整锁状态和 SQL。
怎么快速定位死锁现场
执行 SHOW ENGINE INNODB STATUS\G 后,跳转到 LATEST DETECTED DEADLOCK 区块,重点抓三块:
-
TRANSACTION [id]:两个事务各自的 ID,注意哪个被标记为WE ROLL BACK TRANSACTION (1),这就是 MySQL 选的“牺牲者” -
HOLDS THE LOCK(S):当前事务已持有的锁,例如RECORD LOCKS space id 88 page no 7 index `idx_job_id`,说明它锁住了idx_job_id索引上的某页 -
WAITING FOR THIS LOCK TO BE GRANTED:该事务正在等什么锁,比如RECORD LOCKS space id 88 page no 3 index `PRIMARY`,说明它想锁主键但被另一个事务占着
对照两事务的 HOLDS 和 WAITING FOR,就能画出等待环:A 持 idx_job_id 锁、等 PRIMARY;B 持 PRIMARY 锁、等 idx_job_id——典型的加锁顺序不一致。
为什么错误日志里找不到完整上下文
默认情况下,MySQL 只保留最后一次死锁记录,SHOW ENGINE INNODB STATUS 只能看见最近一次;而生产环境往往高频发生,旧的就被覆盖了。
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
- 临时开启全量记录:
SET GLOBAL innodb_print_all_deadlocks = ON(重启失效) - 永久生效:在
my.cnf的[mysqld]段加innodb_print_all_deadlocks = 1,并确认log_error路径可写 - 注意:开启后所有死锁都会追加进 error log,不清理可能撑爆磁盘
错误日志里那行 Deadlock found when trying to get lock 本身没用,关键在它之后紧跟着的 *** (1) TRANSACTION: 和 *** (2) TRANSACTION: 块,每段里 UPDATE/INSERT 语句才是触发死锁的真实 SQL。
常见死锁模式与对应 SQL 特征
别只看 SQL 文本,要结合表结构和索引判断实际锁范围:
- 出现
gap lock或next-key lock:大概率是范围查询(如WHERE status IN ('pending', 'processing')),或唯一索引冲突前的间隙检查 -
WHERE job_id = ?却锁了整个间隙:说明job_id列没走索引,或索引失效(比如用了函数、隐式类型转换),导致全表扫描+间隙锁扩大 - 两个事务都先
SELECT * FROM t_job WHERE id = ?(快照读),再INSERT INTO t_resume_deliver:可重复读下,插入时会检查唯一索引间隙,若 A 插了 (100,1),B 插 (100,2) 就会因插入意向锁竞争而死锁
真正容易被忽略的是:死锁不是“偶发”,而是加锁顺序不一致在并发足够高时的必然结果。你看到的“偶尔报错”,其实是并发压测或流量高峰才暴露的确定性问题。

















