直接查performance_schema.data_locks是准确定位当前行锁持有者的唯一方式,但需确保performance_schema=ON、global_instrumentation=YES且wait/lock/innodb%相关instrument全启用,否则该表为空;其LOCK_TYPE='RECORD'且LOCK_DATA非NULL时表征真实行锁,须关联INNODB_TRX查TRX_QUERY和TRX_STARTED识别空闲长事务。

直接查 performance_schema.data_locks 是唯一能准确定位“当前谁在持行锁”的方式,其他视图(如 INNODB_LOCKS)在 MySQL 8.0+ 已废弃或不完整,且默认关闭采集。
为什么 data_locks 是首选,但常查不到数据
该表不是“一直有内容”,它依赖三项启用状态:
-
performance_schema必须为ON(检查:SELECT VARIABLE_VALUE FROM performance_schema.variables_by_thread WHERE VARIABLE_NAME = 'performance_schema') -
setup_consumers中global_instrumentation需为YES(否则锁事件不采集) -
setup_instruments里与锁相关的 instrument(如wait/lock/innoDB/table、wait/lock/innoDB/record)必须ENABLED = 'YES'
漏掉任意一项,SELECT * FROM performance_schema.data_locks 就返回空——这不是 bug,是设计如此。
怎么从 data_locks 识别出真正的行锁 SQL
行锁的关键特征是:LOCK_TYPE = 'RECORD' 且 LOCK_DATA 非 NULL(主键或唯一索引命中时才稳定显示值);但要注意:
-
LOCK_DATA在间隙锁(LOCK_MODE含GAP)或非唯一索引下常为NULL或范围值(如7, 10),不能直接用于定位具体行 -
ENGINE_TRANSACTION_ID是关联事务的唯一线索,需用它去INFORMATION_SCHEMA.INNODB_TRX查TRX_QUERY和TRX_STARTED - 一个事务可能同时持多把行锁(多行、多索引),
data_locks每行一条记录,别只取 LIMIT 1 就下结论
如何避免把空闲事务误判为“正在执行 SQL”
常见陷阱:看到 TRX_QUERY 为空,就以为没 SQL 在跑,其实事务可能早就在等提交了。这时:
-
TRX_STATE = 'RUNNING'但TRX_QUERY IS NULL,大概率是应用开了事务却忘了COMMIT或ROLLBACK -
TRX_STARTED时间远早于当前时间(比如几小时之前),而SHOW PROCESSLIST对应线程Command = 'Sleep'、Time很大,基本可确认是“挂起事务” - 不要仅凭
data_locks的LOCK_DATA去反推业务逻辑——它不包含 SQL 上下文,只反映锁对象快照
真正危险的往往不是慢 SQL,而是那些 TRX_QUERY 为空、TRX_STARTED 很老、却还牢牢攥着行锁的空闲事务。它们不会出现在 SHOW PROCESSLIST 的活跃语句里,也容易被 sys.innodb_lock_waits 这类封装视图忽略——必须手动 JOIN data_locks 和 INNODB_TRX 才能揪出来。


















