performance_schema.data_locks是MySQL 8.0+唯一能精确查到SQL所锁索引、行或间隙的实时视图,需手动启用transaction仪器,且必须在事务未提交时立即查询,结合threads和INNODB_TRX联查才能准确定位锁信息。

直接查 performance_schema.data_locks 是唯一可靠方式
MySQL 8.0+ 中,data_locks 是唯一能精确到「哪条 SQL、锁了哪个索引、哪一行(或间隙)」的视图。它不是快照,而是实时捕获引擎层加锁动作。但默认不采集锁信息,必须手动开启:
- 先确认开关已启用:
SELECT COUNT(*) FROM performance_schema.setup_instruments WHERE NAME = 'transaction' AND ENABLED = 'YES';返回 1 才有效 - 若为 0,执行:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'transaction'; -
data_locks中的THREAD_ID需关联performance_schema.threads才能定位是哪个客户端连接
查锁必须在事务未提交时立刻执行
锁是瞬态的——事务一提交、回滚,或语句执行完(非事务级锁),锁就释放了。data_locks 只显示「当前持有中」的锁,查晚了必然为空。
- 错误做法:应用里执行
BEGIN; UPDATE t SET x=1 WHERE id=1; COMMIT;后再查data_locks→ 锁早已消失 - 正确做法:会话 A 执行
BEGIN; UPDATE t SET name='x' WHERE id=5;后**不提交**,会话 B 立即用该会话的THREAD_ID查询:SELECT * FROM performance_schema.data_locks WHERE THREAD_ID = ?; - 普通
SELECT在 RR 隔离级别下不加锁(除非触发一致性读重建),所以不要指望它留下锁痕迹
看懂 LOCK_DATA 和 LOCK_MODE 字段含义
这两个字段才是判断锁类型和范围的核心依据,容易误读:
MySQL 数据库管理技能,能够通过自然语言查询和管理数据库,支持 SELECT/INSERT/UPDATE/DELETE、表管理、备份恢复等操作。当用户提及 MySQL、数据库查询、建表或数据备份时使用此技能。
-
OBJECT_NAME和INDEX_NAME告诉你锁在哪张表、哪个索引上;INDEX_NAME为NULL表示聚簇索引(即主键) -
LOCK_DATA是关键:
– 主键等值匹配时显示具体值,如5
– 二级索引匹配时可能是'Eason', 5(索引列值 + 主键值)
– 间隙锁显示范围,如(5, 10)表示开区间 -
LOCK_MODE中:
–X,REC_NOT_GAP是记录锁(只锁行)
–X,GAP是间隙锁
–X,NEXT_KEY是临键锁(记录锁 + 间隙锁)
–INSERT_INTENTION是插入意向锁(常与间隙锁冲突导致死锁)
别被 EXPLAIN 欺骗:它不反映实际加锁行为
EXPLAIN 只告诉你执行计划是否走索引,完全无法体现锁范围。一个看似“高效”的查询可能引发全表扫描加锁。
-
type = ALL或key = NULL是危险信号,说明没走索引 → InnoDB 会对所有扫描行逐个加X,REC_NOT_GAP锁,效果接近锁表 - 看到
rows = 5就以为只锁 5 行?错。若这 5 行来自全表扫描,那锁的就是扫描路径上的全部 5 行,且无间隙锁区分 - 真正验证锁行为,必须结合
information_schema.INNODB_TRX(找活跃事务 ID)和performance_schema.data_locks(查具体锁对象)联查
最容易被忽略的是锁的「时效性」和「上下文依赖」:同一句 UPDATE,在不同隔离级别(RR vs RC)、不同索引覆盖情况、甚至不同数据分布下,加的锁类型可能完全不同;而 data_locks 查不到结果,90% 是因为查得太晚,不是没加锁。










