mysql中行锁不会真正升级为表锁,所谓“锁表”实为未走索引导致全表扫描,进而对每行聚簇索引记录加record lock或next-key lock,锁大量行后效果等同于表锁。

MySQL
编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。
下载
Record Lock 不会升级为表锁——MySQL InnoDB 从不主动把
Record Lock 升级成
TABLE 级锁。所谓“升级”,是误读;真实情况是:**没走索引 → 全表扫描 → 对每行聚簇索引记录加
Record Lock(或
Next-Key Lock)→ 锁了成千上万行 → 效果等同于表锁,但底层仍是行锁**。
为什么 EXPLAIN 显示 type=ALL 就等于“锁全表”?
InnoDB 的行锁加在索引上,不是加在数据行上。当
WHERE 条件无法命中索引(如字段无索引、
LIKE '%abc'、隐式类型转换),优化器退化为全表扫描:
-
EXPLAIN 中 type = ALL 或 key = NULL 是明确信号
- InnoDB 遍历所有聚簇索引页,对每个扫描到的记录加
X 锁(Record Lock)
- RR 隔离级别下,还会额外加
Gap Lock,锁住所有间隙,进一步扩大范围
- 即使只更新 1 行,只要没索引,也会锁住全部主键记录
performance_schema.data_locks 怎么看出是真表锁还是假“表锁”?
MySQL 8.0+ 必须查
performance_schema.data_locks 才能区分:
-
LOCK_TYPE = 'RECORD':哪怕锁了 10 万行,也是 Record Lock 或 Next-Key Lock
-
LOCK_TYPE = 'TABLE':只有 LOCK TABLES t WRITE、ALTER TABLE、TRUNCATE 等操作才会出现
- 别信
SHOW ENGINE INNODB STATUS\G 里 “HOLDS THE LOCK(S)” —— 它只显示最近事务,漏掉静默持有者
哪些操作看似像锁升级,实则完全无关?
这些不是行锁“升级”,而是独立机制触发的真表级行为:
-
LOCK TABLES t WRITE:会话级独占锁,后续所有 DML 被拦,SELECT ... FOR UPDATE 直接报 ERROR 1100
-
ALTER TABLE / TRUNCATE TABLE:由 Server 层元数据锁(MDL)控制,阻塞所有并发 DML
- MyISAM 表任意写操作:该引擎压根不支持行锁,
UPDATE 就是表锁
- 未命中主键/唯一索引的
INSERT:InnoDB 对自增段加锁,高并发下表现接近表锁,但仍是索引粒度
真正要盯住的,永远是那条语句有没有走索引——锁范围宽窄,不在锁本身,而在执行计划。