SHOW ENGINE INNODB STATUS\G 是唯一可靠、零配置、不依赖日志的实时死锁排查入口,其 LATEST DETECTED DEADLOCK 区块精准记录事务间 HOLD 与 WAIT 的循环锁关系、索引名、页号、锁类型及末尾 SQL,可直接定位环路等待根源。

直接执行 SHOW ENGINE INNODB STATUS\G,立刻看到最近一次死锁的完整现场——这是唯一可靠、零配置、不依赖日志文件的实时入口。
为什么不能只靠错误日志查死锁
应用层报错 ERROR 1213 (40001): Deadlock found when trying to get lock 只告诉你“发生了”,不告诉你“谁卡了谁、在哪卡的”。错误日志(如 /var/log/mysql/error.log)默认不记录死锁详情,除非你提前开启 innodb_print_all_deadlocks = ON。但即使开了,日志里混着启动信息、连接断开、慢查询等噪音,定位成本高。而 SHOW ENGINE INNODB STATUS\G 的 LATEST DETECTED DEADLOCK 区块是 MySQL 自动维护的“快照缓存”,发生即存、覆盖前一直可用,精准且即时。
怎么看懂 LATEST DETECTED DEADLOCK 里的事务关系
重点盯住两个事务块开头的 *** (1) TRANSACTION 和 *** (2) TRANSACTION,它们不是按时间顺序编号,而是日志标记;真正关键的是下面三组字段:
-
HOLDS THE LOCK(S):这个事务当前“攥着哪些锁”——记下索引名(如`idx_account`)、页号(page no 7)、锁类型(lock_mode X表示排他锁) -
WAITING FOR THIS LOCK TO BE GRANTED:这个事务“在等哪个锁被释放”——同样看索引、页号、锁模式 - 末尾的
SQL语句(如UPDATE accounts SET balance = ? WHERE user_id = ?):这是你能回溯业务逻辑的唯一锚点,务必抄下来
如果发现事务1在等 idx_account 上的锁,而该锁正被事务2持有;同时事务2又在等 PRIMARY 上的锁,而该锁可能被事务1持有——这就是典型的访问顺序不一致导致的环路等待。
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
常见误读和必须补的操作
死锁日志里的 SQL 经常不完整:ORM(如 MyBatis)生成的预编译语句只显示 WHERE id = ?,参数值不会展开;information_schema.INNODB_TRX 表能帮你补全上下文:
SELECT trx_id, trx_state, trx_started, trx_query FROM information_schema.INNODB_TRX WHERE trx_id IN ('12345', '12346');另外,别指望 innodb_status_output_locks = ON 帮你理清逻辑——它会让输出膨胀数倍,全是锁地址和内存结构,反而掩盖事务行为本质。线上环境禁用。
确认死锁是否真被解决,得看回滚动作是否生效
日志末尾一定有类似 *** WE ROLL BACK TRANSACTION (1) 的明确声明。这说明 MySQL 已介入并强制终止其中一个事务。但要注意:被回滚的事务未必是“写得更错”的那个,而是“加锁代价更低”的那个(比如持有的锁更少、等待时间更短)。所以修复重点不是“避免被回滚”,而是打破等待环路——统一所有业务路径的索引访问顺序,比如所有涉及 users 和 orders 的更新,都先查/改 users 再操作 orders,绝不交叉。

















