MySQL RC与RR隔离级别区别及实战锁机制详解
在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启动并更新ID为1的行:
begin; update a set d='20' where a='1'; commit; - 事务2尝试更新ID为2的行:
此时事务2会因为获取不到锁而阻塞,最终因超过等待时间报错begin; update a set d='20' where a='2';ERROR 1205 (HY005): Lock wait timeout exceeded。
原因分析:在RR模式下,由于没有走索引,InnoDB无法精确定位到单条记录,进而对该范围内的所有索引/数据行施加了间隙锁(GAP Lock),导致其他事务即使更新不同的行也会发生冲突。
第三步骤:有索引条件下的锁表现
若利用索引 index_b_c 进行查询,锁粒度会缩小:
- 事务1:更新
b='2'(命中索引行id=2)。 - 事务2:更新
b='3'(命中索引行id=3)。
此时两个操作可以同时运行。这是因为它们各自仅锁定了特定的索引行及相应的间隙,互不干扰。通过 performance_schema.data_locks 可观察到具体的Lock Mode。
验证结论:在使用RR隔离级别时,如果更新条件未命中索引,极大概率会导致大范围甚至全表级别的锁等待。
RC隔离级别下的锁表现
修改全局设置开启RC模式:
set global transaction_isolation='read-committed';
第四步骤:非索引更新测试
在无索引字段上进行多事务并发操作:
- 事务1:修改
a='1'的记录。 - 事务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的主要区别决定了应用场景的选择:
- 并发优先选RC:RC下不持有间隙锁,非命中索引的行在执行完操作后会迅速释放锁资源,极大降低了死锁风险和等待时间。
- 强一致性选RR:RR保证了事务内多次读取的一致性,消除了幻读,适合对数据一致性要求极高但不介意一定程度性能损耗的场景。
- 运维注意:若强制将默认隔离级别改为RC,需确保Binlog格式设置为
row或mixed。
以上就是MySQL中隔离级别RC与RR的区别及锁机制的详细解读,更多关于MySQL高性能配置的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













