rc隔离级别下仍存在间隙锁,是因为唯一键/外键冲突检测必须加s型next-key lock(record+gap)以防止并发插入重复值,这是官方明确规定的例外行为,与普通范围查询无关。

RC隔离级别不能消除死锁,只能降低部分场景的死锁概率;真正引发死锁的,是唯一键/外键冲突检测、索引缺失、加锁顺序不一致等底层行为,和隔离级别无关。
RC下为什么还有间隙锁?
很多人误以为“RC = 没有间隙锁”,这是对文档的断章取义。MySQL官方明确说明:gap locking is used only for foreign-key constraint checking and duplicate-key checking。也就是说:
- 普通
SELECT或UPDATE带范围条件(如WHERE age > 25)时,RC 下确实不加间隙锁 - 但只要涉及唯一索引冲突判断(比如
INSERT ... ON DUPLICATE KEY UPDATE或REPLACE INTO),InnoDB 仍会加S型 Next-Key Lock(Record + Gap)来校验重复 - 外键约束检查同理,哪怕在 RC 下也会触发间隙锁
INSERT类语句在RC下怎么死锁的?
典型死锁链往往来自并发插入相同唯一值,例如两个事务同时执行:
INSERT INTO users (id, email) VALUES (100, 'a@b.com') ON DUPLICATE KEY UPDATE lastmodified = NOW();
此时:
- 两者都会先对已存在的
'a@b.com'记录加S型 Next-Key Lock(用于冲突检测) - 接着都尝试插入新行,需申请
X型插入意向锁(insert intention lock) -
S锁与X锁互斥 → 直接形成循环等待 - 这个过程在 RR 和 RC 下行为完全一致
为什么改了RC,线上还是报死锁?
最常见原因是配置没真正生效:
- MySQL 全局默认仍是
REPEATABLE-READ,连接池(如 HikariCP)复用连接后,@@transaction_isolation仍为服务端默认值 - ORM(如 MyBatis)未在每次获取连接后显式执行
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED - 验证是否生效,必须在业务 SQL 执行前查
SELECT @@transaction_isolation,而不是看@@global.transaction_isolation
哪些操作在RC下反而更容易暴露死锁?
RC 减少了间隙锁覆盖范围,看似“更松”,但会放大两类问题:
-
无索引查询:
WHERE条件没走索引时,RC 下仍会全表扫描并逐行加 Record Lock,锁数量暴增,与其他事务交叉概率更高 -
批量删+增混合:比如“先
DELETE WHERE biz_id = ?,再INSERT ... ON DUPLICATE KEY UPDATE”,若biz_id是唯一联合索引的一部分,删除和插入可能锁定不同间隙,顺序稍有错位就死锁
真正决定死锁风险的,从来不是隔离级别本身,而是你写的 SQL 是否精确命中索引、事务是否短小、多点更新是否顺序统一——这些,RC 一个都不会帮你自动修正。











