mysql 5.7及更早版本可通过innodb_lock_waits视图直接定位锁等待关系,而8.0+需改用performance_schema.data_lock_waits;无论版本,首查innodb_trx中trx_state为lock wait的事务才是排查锁问题最可靠起点。

MySQL 5.7 及更早版本:直接查 INNODB_LOCK_WAITS 表能定位谁在等谁
INNODB_LOCK_WAITS 是 InnoDB 提供的锁等待关系视图,只存在于 MySQL 5.7 及之前版本(MySQL 8.0+ 已移除)。它不展示锁本身,而是明确告诉你“哪个事务在等哪个事务”,是快速揪出阻塞源头的第一站。
执行以下查询即可看到实时等待链:
SELECT r.trx_id AS waiting_trx_id, r.trx_mysql_thread_id AS waiting_thread, r.trx_query AS waiting_query, b.trx_id AS blocking_trx_id, b.trx_mysql_thread_id AS blocking_thread, b.trx_query AS blocking_query FROM information_schema.INNODB_LOCK_WAITS w INNER JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.INNODB_TRX r ON r.trx_id = w.requesting_trx_id;
- 如果结果为空,说明当前没有活跃的锁等待(但不代表没锁,可能只是没排队)
-
waiting_query被截断?补一句SHOW FULL PROCESSLIST,用waiting_thread对应的 ID 找完整 SQL - 注意
blocking_query可能是NULL—— 持锁事务可能已提交但未清理,或正在执行无查询语句的操作(如空事务 sleep) - 该表依赖
INNODB_TRX,若后者查不到记录,INNODB_LOCK_WAITS必然为空,需先确认事务是否真的活跃
MySQL 8.0+:INNODB_LOCK_WAITS 已失效,必须切到 performance_schema.data_lock_waits
MySQL 8.0 彻底废弃了 INNODB_LOCKS 和 INNODB_LOCK_WAITS,所有锁元数据统一收口到 performance_schema。但默认不采集锁事件,不启用就查不到任何内容。
- 先确认采集开关已开:
SELECT NAME, ENABLED FROM performance_schema.setup_instruments WHERE NAME LIKE 'wait/lock/%';,若ENABLED为NO,执行UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'wait/lock/%'; - 再查等待关系:
SELECT * FROM performance_schema.data_lock_waits;,关键字段是BLOCKING_ENGINE_LOCK_ID和REQUESTING_ENGINE_LOCK_ID - 要关联到具体事务和 SQL,得连查
data_locks和events_statements_current:data_locks.LOCK_TRX_ID对应events_statements_current.THREAD_ID,不能直接连TRX_ID - 该视图返回的是引擎级锁 ID,不是事务 ID,别试图用它去
KILL—— 得回INNODB_TRX查trx_mysql_thread_id
为什么查了 INNODB_LOCK_WAITS 却看不到阻塞事务的 SQL?
常见现象:等待事务能看见 trx_query,但阻塞方显示 NULL 或一条无关语句。这不是 bug,而是 InnoDB 锁模型的自然表现。
- 持锁事务可能刚执行完
UPDATE就停在那儿了(比如应用忘了COMMIT),后续没新语句,trx_query就为空 - 事务里执行了 DDL(如
ALTER TABLE),会升级为元数据锁(MDL),而INNODB_TRX不记录 MDL 操作,此时得查performance_schema.metadata_locks -
SELECT ... FOR UPDATE后没做任何更新,只读事务也可能长期持锁 —— 它的trx_query就是那条SELECT,但容易被忽略,以为“只是查,不该锁” - 真正卡住的往往不是最后那条 SQL,而是前面没提交的事务。重点看
trx_started时间戳,比其他事务早得多的那个,大概率是根因
查不到锁等待?先排除 INNODB_TRX 里有没有 LOCK WAIT 状态
INNODB_LOCK_WAITS(或 data_lock_waits)本质是“等待关系”的快照,它只反映当前正处在等待中的事务。如果锁已超时回滚、或等待刚发生还没刷入视图,就查不到。最稳的第一步永远是看 INNODB_TRX。
- 执行
SELECT * FROM information_schema.INNODB_TRX\G,逐行扫trx_state字段 - 只要看到
trx_state: LOCK WAIT,就证明存在锁等待,哪怕INNODB_LOCK_WAITS还没刷新出来 - 配合
trx_wait_started判断等待时长;若超过innodb_lock_wait_timeout(默认 50 秒),事务会被自动 kill,但日志里会留痕 - 这个表在所有 MySQL 版本都可用,且无需额外开启 instrumentation,是排查锁问题不可跳过的起点
真实锁竞争往往藏在“看似正常”的长事务里,而不是报错那一刻。盯住 trx_state 和 trx_started,比死磕锁视图更快定位根因。











