MySQL RC与RR隔离级别区别及实战锁机制详解

慢慢来
慢慢来
发布时间:2026-10-16 | 6人浏览过
原创

在MySQL数据库中,RR(Repeatable Read,可重复读)是默认的隔离级别,而RC(Read Committed,读已提交)则具有更高的并发度。两者最核心的区别在于RR采用Next-Key Lock解决幻读问题,可能导致范围查询时锁住更多记录;而RC仅锁定具体行,且每条SELECT语句产生独立的一致性快照。

核心差异:加锁机制与并发性能

理解锁的机制是选择隔离级别的关键:

  • RR隔离级别:支持 GAP Lock(间隙锁)。为了彻底解决幻读问题,它会对符合条件的数据进行行锁并扩展至区间间隙。
  • RC隔离级别:不使用GAP Lock。它通过非索引列过滤后,会释放不满足条件的行锁。虽然这违反了严格的“两阶段加锁原则”,但显著减少了锁竞争,降低了死锁和锁超时的概率,并发性能优于RR。
  • BINLOG兼容性:RC隔离级别不支持 STATEMENT 格式的binlog(易导致主从数据不一致),必须使用 MIXED 或 ROW 格式。这也是MySQL默认设为RR的重要原因之一。
  • 一致性读快照(ReadView):RC下每一条SELECT都拥有自己的ReadView(读取执行时已提交的最新数据);RR下整个事务共享同一个ReadView(以第一条SELECT为准)。

第一步骤:创建测试数据

首先构建一个基础测试表,包含普通字段和非唯一索引,用于观察不同条件下的锁行为。

create table a (
id int auto_increment,
a varchar(10),
b varchar(10),
c varchar(10),
d varchar(10),
 primary key(id) 
) engine=INNODB default charset=utf8;

insert into a(a,b,c,d) values 
('1','1','1','1'),('2','2','2','2'),('3','3','3','3'),
('4','4','4','4'),('5','5','5','5'),('6','6','6','6');

CREATE INDEX index_b_c ON a(b,c); 

RR隔离级别下的锁表现

查看当前系统隔离级别:

show variables like '%iso%';
-- Variable_name: transaction_isolation | Value: REPEATABLE-READ

第二步骤:无索引条件下的锁表现

当 WHERE 条件走全表扫描(无索引)时,RR级别会表现出类似锁全表的行为:

  1. 事务1启动并更新ID为1的行:
    begin; update a set d='20' where a='1'; commit;
  2. 事务2尝试更新ID为2的行:
    begin; update a set d='20' where a='2'; 
    此时事务2会因为获取不到锁而阻塞,最终因超过等待时间报错 ERROR 1205 (HY005): Lock wait timeout exceeded。

原因分析:在RR模式下,由于没有走索引,InnoDB无法精确定位到单条记录,进而对该范围内的所有索引/数据行施加了间隙锁(GAP Lock),导致其他事务即使更新不同的行也会发生冲突。

第三步骤:有索引条件下的锁表现

若利用索引 index_b_c 进行查询,锁粒度会缩小:

  1. 事务1:更新 b='2'(命中索引行id=2)。
  2. 事务2:更新 b='3'(命中索引行id=3)。

此时两个操作可以同时运行。这是因为它们各自仅锁定了特定的索引行及相应的间隙,互不干扰。通过 performance_schema.data_locks 可观察到具体的Lock Mode。

验证结论:在使用RR隔离级别时,如果更新条件未命中索引,极大概率会导致大范围甚至全表级别的锁等待。

RC隔离级别下的锁表现

修改全局设置开启RC模式:

set global transaction_isolation='read-committed';

第四步骤:非索引更新测试

在无索引字段上进行多事务并发操作:

  1. 事务1:修改 a='1' 的记录。
  2. 事务2:修改 a='2' 的记录。由于RC不包含Gap Lock,此处不会发生长时间锁等待,事务可以顺利执行并提交。

在事务2中执行 SELECT,可以看到事务1已提交(commit)的数据变更。这证明了RR隔离级别的“不可重复读”现象——即在同一事务中多次读取同一条记录,结果可能因为其他事务的提交而发生变化。

第五步骤:锁结构验证

通过查询视图确认此时的锁状态:

-- 数据锁情况
select * from performance_schema.data_locks;
-- LOCK_MODE: X,REC_NOT_GAP (只有行锁,没有间隙锁)

-- 事务等待情况
select * from data_lock_waits;
-- Empty set (无阻塞)

总结

RC与RR的主要区别决定了应用场景的选择:

  1. 并发优先选RC:RC下不持有间隙锁,非命中索引的行在执行完操作后会迅速释放锁资源,极大降低了死锁风险和等待时间。
  2. 强一致性选RR:RR保证了事务内多次读取的一致性,消除了幻读,适合对数据一致性要求极高但不介意一定程度性能损耗的场景。
  3. 运维注意:若强制将默认隔离级别改为RC,需确保Binlog格式设置为 row 或 mixed。

以上就是MySQL中隔离级别RC与RR的区别及锁机制的详细解读,更多关于MySQL高性能配置的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表