explain无法判断行锁或表锁,它只显示执行计划;实际锁类型需通过information_schema或performance_schema中的锁视图(如data_locks)查看lock_mode字段确认。

EXPLAIN 看不出行锁还是表锁
MySQL 的 EXPLAIN 只展示查询执行计划(比如是否走索引、用哪个索引、扫描多少行),它**完全不体现锁类型或锁等待状态**。想通过 EXPLAIN 判断是行锁还是表锁,这条路走不通。
真正能反映锁行为的,是事务运行时的实时状态,不是预估的执行计划。
-
EXPLAIN中的type为ALL或index且没走有效索引 → 实际执行时很可能触发表级锁(尤其在 MyISAM 或 InnoDB 的某些全表扫+无索引更新场景) -
EXPLAIN显示走了range/ref等索引访问 → 行锁可能性高,但不保证:如果索引失效(如对索引字段做函数操作)、或用了SELECT ... FOR UPDATE但 WHERE 条件没命中索引,InnoDB 仍可能升级为表锁 - 唯一能从
EXPLAIN间接推测锁粒度的,是看key列是否非NULL、rows是否明显偏大——但这只是线索,不是证据
查锁实际类型得看 information_schema
要确认当前有没有锁、是什么锁、锁在哪,必须查 information_schema 下的三张表:
-
INNODB_TRX:看当前活跃事务,重点关注TRX_ID、TRX_STATE(比如LOCK WAIT)、TRX_MYSQL_THREAD_ID -
INNODB_LOCKS(MySQL 5.7 及以前)或performance_schema.data_locks(8.0+):直接列出每个锁的LOCK_TRX_ID、LOCK_MODE(如X,REC_NOT_GAP是行锁,TABLE是表锁)、LOCK_DATA(被锁的具体记录值) -
INNODB_LOCK_WAITS(5.7)或performance_schema.data_lock_waits(8.0+):谁在等谁,BLOCKING_TRX_ID指向持锁事务
例如,在 8.0 中快速定位锁等待:
SELECT * FROM performance_schema.data_locks WHERE LOCK_TRX_ID IN ( SELECT TRX_ID FROM information_schema.INNODB_TRX WHERE TRX_STATE = 'LOCK WAIT' );
注意:LOCK_MODE 字段里带 REC_NOT_GAP 或 RECORD 就是行锁;出现 TABLE 就是表锁;GAP 是间隙锁,也属于行级锁范畴。
什么情况下行锁会退化成表锁
InnoDB 行锁不是绝对的,以下情况会导致锁范围扩大甚至升级为表锁:
- UPDATE/DELETE 语句的 WHERE 条件**没走任何索引**(包括主键、唯一键、普通索引)→ InnoDB 无法精确定位记录,只好锁整张表
- WHERE 条件用了**函数或表达式**导致索引失效,例如
WHERE YEAR(create_time) = 2024(即使create_time有索引) - 使用
SELECT ... FOR UPDATE或LOCK IN SHARE MODE时,**扫描过程中遇到大量不满足条件的记录**,且隔离级别是REPEATABLE READ→ 可能加大量间隙锁(GAP),看起来像“锁了一大片” - 显式执行
LOCK TABLES ... WRITE→ 这是真正的表锁,和 InnoDB 引擎层无关,会阻塞所有其他线程对该表的读写
特别注意:没有主键或唯一索引的 InnoDB 表,UPDATE/DELETE 几乎必然退化为表锁,因为 InnoDB 内部依赖聚簇索引定位行。
模拟锁等待并验证锁类型的操作步骤
想亲眼看到行锁 vs 表锁的区别,最可靠的方式是手动构造并发场景,再查锁视图:
- 开两个 MySQL 客户端连接(记为 A 和 B)
- A 执行:
BEGIN; UPDATE t_user SET name='a' WHERE id=100;(假设id是主键)→ 此时只锁住这一行 - B 执行:
UPDATE t_user SET name='b' WHERE id=100;→ 会被阻塞,查performance_schema.data_locks可见LOCK_MODE是X,REC_NOT_GAP - 换一个场景:A 执行
UPDATE t_user SET name='x' WHERE status=0;(status无索引)→ B 执行任意UPDATE t_user都会被卡住,查锁会发现LOCK_MODE是TABLE
关键点:必须在另一个事务处于 LOCK WAIT 状态时立刻查 data_locks,否则锁释放后记录就没了。别指望 EXPLAIN 给你答案,它连锁的影子都看不到。











