查不到死锁记录是因为InnoDB检测到死锁后立即回滚事务并清理INNODB_LOCK_WAITS中的等待关系,该表仅为瞬时快照;应优先查看SHOW ENGINE INNODB STATUS中的LATEST DETECTED DEADLOCK段或开启innodb_print_all_deadlocks=ON捕获日志。

查 INFORMATION_SCHEMA.INNODB_LOCK_WAITS 前先确认是否真有死锁
MySQL 不会把所有锁等待都记为死锁,只有被 InnoDB 主动检测并回滚掉的事务才会写入 INNODB_LOCK_WAITS。所以你查不到记录,不等于没锁争用——可能只是普通锁等待(超时后报 Lock wait timeout exceeded),或者死锁刚发生就被清掉了。
真正要定位死锁,优先看错误日志里的死锁详情(SHOW ENGINE INNODB STATUS\G 输出的 LATEST DETECTED DEADLOCK 段),它包含事务 ID、SQL、持有/等待的锁、回滚决策,比 INNODB_LOCK_WAITS 更直接。
-
INNODB_LOCK_WAITS是“快照视图”,只反映查询时刻的等待链,不保留历史 - 该表在 MySQL 8.0.1+ 才默认启用;5.7 需确保
innodb_status_output_locks=ON且启用了 performance_schema - 字段如
REQUESTING_TRX_ID和BLOCKING_TRX_ID是十六进制字符串,需转成十进制才能关联INNODB_TRX表
用 INNODB_TRX + INNODB_LOCKS + INNODB_LOCK_WAITS 连查还原死锁现场
单看 INNODB_LOCK_WAITS 只能知道谁在等谁,没法看到 SQL 和锁类型。必须三表 JOIN 才能拼出完整上下文:
SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread, r.trx_query waiting_query, b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS w JOIN INFORMATION_SCHEMA.INNODB_TRX b ON b.trx_id = w.BLOCKING_TRX_ID JOIN INFORMATION_SCHEMA.INNODB_TRX r ON r.trx_id = w.REQUESTING_TRX_ID;
-
INNODB_LOCKS表在 MySQL 8.0.24+ 已废弃,改用performance_schema.data_locks,但日常排查仍可依赖上面三表组合 - 如果
blocking_query为NULL,说明阻塞方是隐式锁(比如唯一索引冲突导致的插入意向锁)或已提交/回滚,此时需结合INNODB_LOCKS(或 8.0+ 的data_locks)查锁对象 - 注意
trx_state字段:阻塞方若为LOCK WAIT,说明它自己也在等别的锁,可能是锁链而非根因
为什么 INNODB_LOCK_WAITS 查不到刚发生的死锁?
因为 InnoDB 在检测到死锁后,会立刻选择一个事务回滚,并清理其持有的锁和对应记录——包括从 INNODB_LOCK_WAITS 中删除该等待关系。所以你执行查询时,很可能已经“人去楼空”。
- 死锁日志(
SHOW ENGINE INNODB STATUS)是唯一带时间戳、不可篡改的证据,务必第一时间捕获 - 生产环境建议开启
innodb_print_all_deadlocks=ON,把每次死锁追加写入 error log,避免被后续SHOW ENGINE覆盖 -
performance_schema的events_statements_history_long表可回溯线程最近执行的 SQL,配合线程 ID 能定位到触发死锁的具体语句
别只盯着锁表,先看业务 SQL 是否顺序错乱
90% 的死锁源于应用层未按固定顺序访问多张表或多个索引。比如事务 A 先更新 users 再更新 orders,事务 B 反过来,就极易形成环路。
- 检查是否有
UPDATE ... WHERE语句缺失索引,导致全表扫描加锁(行锁升级为表锁风险) - 批量更新尽量用主键 or 索引列 in-list,避免非唯一索引范围扫描引发间隙锁冲突
- 长事务(
trx_state='RUNNING'且trx_started很早)会拖住锁不放,是死锁温床,监控时重点关注trx_started和trx_duration
死锁不是配置问题,是并发逻辑暴露了数据访问顺序的脆弱性。锁表信息只是线索,真正要改的是 SQL 执行路径和事务边界。


















