直接查innodb_lock_waits可快速定位锁等待关系,它明确显示requesting_trx_id(等待方)和blocking_trx_id(阻塞方),但该表在mysql 8.0.24+已废弃,应迁移到performance_schema.data_lock_waits;其记录为瞬时快照,事务提交或回滚后即消失,查不到时需结合show engine innodb status的transactions部分分析。

直接查 INNODB_LOCK_WAITS 能看到谁卡住谁
这是最快速定位锁等待关系的入口。它不展示锁本身,只明确告诉你「哪个事务在等、哪个事务在挡路」。只要表里有记录,就说明当前存在活跃的锁等待,无需再猜。
关键字段:requesting_trx_id 是等待方,blocking_trx_id 是持有锁并导致阻塞的一方。这两 ID 可直接去 INNODB_TRX 表里查对应 SQL 和事务状态。
-
INNODB_LOCK_WAITS在 MySQL 5.6+ 都存在,但 MySQL 8.0.24+ 后被标记为废弃,建议尽快迁移到performance_schema.data_lock_waits - 该表是内存视图,只反映“此刻正在发生的等待”,事务一提交或回滚,记录立刻消失
- 如果查不到记录,不代表没锁问题——可能是等待刚发生还没刷入,也可能是已超时回滚,此时得看
SHOW ENGINE INNODB STATUS的TRANSACTIONS小节
INNODB_TRX 里找等待事务的 SQL 和耗时
光知道谁挡路不够,得知道它在干啥、卡了多久。INNODB_TRX 提供了每个活跃事务的完整快照:SQL 语句(trx_query)、开始时间(trx_started)、等待时长(trx_wait_started)、锁等待状态(trx_state)。
重点关注状态为 LOCK WAIT 的行,它的 trx_wait_started 时间戳能帮你判断是否已接近 innodb_lock_wait_timeout 默认值(50 秒),避免盲目等超时。
-
trx_mysql_thread_id可用于关联SHOW PROCESSLIST,确认该事务来自哪个应用连接 -
trx_isolation_level值如REPEATABLE READ暗示可能涉及间隙锁,而READ COMMITTED下间隙锁不生效,可辅助判断锁范围 - 若
trx_query为空,说明事务处于空闲状态(比如只执行了BEGIN还没发 SQL),这类长空闲事务最容易成为隐形阻塞源
用 JOIN 一次性查出等待方 + 持有方 + 对应 SQL
单独查三张表太慢,生产环境推荐一条 SQL 直出完整链条。下面这个查询在 MySQL 5.7–8.0.23 通用:
SELECT r.trx_id AS waiting_trx_id,
r.trx_query AS waiting_query,
b.trx_id AS blocking_trx_id,
b.trx_query AS blocking_query,
b.trx_started AS blocking_started,
TIMESTAMPDIFF(SECOND, b.trx_started, NOW()) AS blocking_duration_sec
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;
注意:blocking_query 可能为 NULL ——不是 bug,而是持有锁的事务当前没在执行 SQL(例如刚 UPDATE 完还没 COMMIT),此时要重点看 blocking_started 和持续时间。
- 若
blocking_duration_sec超过 30 秒,基本可判定是长事务未提交,而非正常业务逻辑 - 若
waiting_query是UPDATE或DELETE,而blocking_query是SELECT ... FOR UPDATE,说明读写顺序不一致,容易引发死锁 - MySQL 8.0.24+ 必须改用
performance_schema.data_lock_waits+data_locks,字段名和关联方式完全不同,不能直接套用
为什么有时 INNODB_LOCK_WAITS 查不到,但业务明显卡住
常见于两种情况:一是锁等待刚发生,尚未刷新到该表;二是事务已因超时回滚,表里记录被清空,但错误已抛给应用(报错 ERROR 1205 (HY000): Lock wait timeout exceeded)。
这时必须立刻执行 SHOW ENGINE INNODB STATUS\G,人工翻到 TRANSACTIONS 部分,找状态为 LOCK WAIT 或 ACTIVE 且 mysql tables in use 非零的事务。里面会明确写出「waiting for this lock to be granted」和「holds the lock(s)」的索引名与记录位置。
- 该命令输出是单次快照,不自动刷新,执行完就得马上复制保存,否则下次执行内容可能已变
- 输出中若出现
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:后跟一堆十六进制地址,说明锁对象不在主键/二级索引上,可能落在隐式锁或外键约束上,需结合SHOW CREATE TABLE看表结构 - 别依赖
information_schema.INNODB_LOCKS(5.7 已废弃),它在高并发下数据可能不一致,仅作辅助参考











