Record Lock 是 InnoDB 中对索引记录加的锁,即常说的“行锁”,但它锁的是索引项而非物理行;等值查询命中唯一索引时加 Record Lock(rec_not_gap),未命中则退化为 Gap Lock。

Record Lock 是什么,和行锁是一回事吗
Record Lock 就是常说的“行锁”,但它不是锁在表的物理行上,而是锁在索引记录上。InnoDB 没有真正的“行锁”概念,只有索引锁——Record Lock 锁的是索引中某一条具体的索引项,比如主键索引里的 id = 5 这个值对应的位置。
它分两种模式:S(共享锁,如 SELECT ... LOCK IN SHARE MODE)和 X(排他锁,如 SELECT ... FOR UPDATE 或 UPDATE/DELETE)。只要索引唯一且查询等值命中,Record Lock 就不会扩散到间隙,这是它最轻量、最不阻塞的形态。
主键等值查询一定加 Record Lock 吗
不一定,取决于记录是否存在:
- 查
id = 5,而表里真有id = 5的记录 → 加Record Lock(lock_mode显示为rec_not_gap),只锁这一行,其他事务还能插id = 5(但会因主键冲突报错,不是被锁住) - 查
id = 7,而表里没有id = 7→ 不加Record Lock,而是加Gap Lock,比如锁住(5, 10)这个间隙,防止别人插入7
关键判断依据是:MySQL 在唯一索引上做等值查找时,Next-Key Lock(默认加锁单位)会退化——存在则退成 Record Lock,不存在则退成 Gap Lock。
怎么验证当前加的是 Record Lock 而不是 Gap Lock
直接查 performance_schema.data_locks 表最可靠:
SELECT engine_transaction_id, object_name, index_name,
lock_type, lock_mode, lock_data
FROM performance_schema.data_locks
WHERE object_name = 't1' AND lock_type = 'RECORD';
重点关注 lock_mode 字段:
-
X,rec_not_gap或S,rec_not_gap→ 确实是Record Lock -
X,gap或S,gap→ 是间隙锁,没锁到记录本身 -
X,next-key→ 临键锁,说明不是唯一索引,或用了范围条件
注意:Gap Lock 在 INFORMATION_SCHEMA.INNODB_TRX 里不可见,只能靠 SHOW ENGINE INNODB STATUS\G 看到 lock_mode X locks gap before rec 这类提示。
Record Lock 在非主键唯一索引上表现一样吗
逻辑一致,但锁的位置不同:主键是聚簇索引,锁的是数据行本身;唯一二级索引(比如 UNIQUE KEY uniq_i1(i1))上加 Record Lock,锁的是该二级索引条目,同时会隐式在主键上加一把 Record Lock(因为要保证一致性读和更新可见性)。
这意味着:即使你只用 i1 = 11 查询并加锁,实际会锁住两条索引记录——uniq_i1 索引上的 i1 = 11 条目,以及主键索引上对应的那行 id = 1。这个隐式主键锁常被忽略,却可能成为死锁源头。


















