默认data_locks表为空,因innodb锁采集器(如wait/lock/innodb/record)默认关闭且需重启mysql并配置performance-schema-instrument='wait/lock/innodb%=on'才能启用。

能查,但默认不返回你想要的锁——data_locks 表本身是空的,除非你手动启用对应采集器。
为什么 SELECT * FROM performance_schema.data_locks 返回空或只有表锁
MySQL 8.0+ 默认开启 performance_schema,但锁相关的采集器(instruments)默认是关闭的。这意味着 data_locks 不会记录任何行级锁、间隙锁或 next-key 锁,只可能有极少数系统自动加的表锁。
-
SELECT @@performance_schema返回1≠ 锁采集已开 -
SELECT * FROM performance_schema.setup_instruments WHERE NAME LIKE 'wait/lock/innodb%'才是关键:若ENABLED = 'NO',data_locks就基本没用 - 常见漏配项:
wait/lock/innodb/table(表锁)、wait/lock/innodb/record(行锁)、wait/lock/innodb/lock(锁结构本身)必须全为YES - 运行时无法动态开启
wait/lock/innodb/record类 instrument,必须重启 MySQL 并在配置文件中加:performance-schema-instrument='wait/lock/innodb%=ON'
查到锁了,但 LOCK_DATA 是 supremum pseudo-record 或 NULL 怎么办
LOCK_DATA 只对 record lock(主键/唯一索引上的精确匹配)稳定显示具体值;一旦涉及 gap lock、next-key lock 或非唯一二级索引扫描,它就不可靠——不是 bug,是 InnoDB 内部表示方式决定的。
- 例如:
DELETE FROM t WHERE name = 'xxx'(name是非唯一索引),LOCK_DATA可能为空或只显示name值,不带主键,无法直接定位行 -
supremum pseudo-record表示“间隙上界”,说明这个锁是纯 gap lock,没锁任何真实数据行 - 别依赖
LOCK_DATA去反查业务数据;应结合OBJECT_NAME、INDEX_NAME和原始 SQL 判断影响范围 - 想确认是否真锁了某行?用
SELECT * FROM t WHERE id = X FOR UPDATE尝试触发冲突,比看LOCK_DATA更直接
如何关联锁和正在执行的 SQL 语句
data_locks.THREAD_ID 是线程 ID,不是连接 ID,也不能直接对应 INFORMATION_SCHEMA.INNODB_TRX.trx_mysql_thread_id。要看到“谁在执行什么语句持了这个锁”,得串三张表:
- 先从
data_locks拿出THREAD_ID和ENGINE_TRANSACTION_ID - 用
THREAD_ID关联performance_schema.threads得到PROCESSLIST_ID(即SHOW PROCESSLIST里的 ID) - 再用
THREAD_ID查performance_schema.events_statements_current或events_statements_history(后者需确保 history 开启且未被轮转)拿到最近执行的SQL_TEXT - 注意:
events_statements_current只存当前正在执行的语句;如果事务已暂停(比如等锁),这条记录可能为空,得查history
真正难的不是查出锁,而是理解锁为何存在——data_locks 给的是快照,不是因果。比如一个 UPDATE 看似只改一行,却因走非唯一索引而加了 5 个间隙锁,data_locks 会列 5 条记录,但不会告诉你“因为条件没走主键所以扩大了范围”。这得靠你对隔离级别、索引结构和加锁规则的判断。











