RC和RR隔离级别下MVCC的差异?

读已提交(RC)和可重复读(RR)是 InnoDB 中基于 MVCC 实现的两个核心隔离级别,二者的核心差异在于 Read View 的生成时机,这直接导致了快照读的一致性、版本可见性判断的不同

我们从核心差异点、行为对比、实例验证三个维度拆解,结合之前的版本链、Read View 知识,帮你彻底理清。

一、核心差异:Read View 的生成时机

这是 RC 和 RR 隔离级别下 MVCC 行为差异的根源,没有之一。

隔离级别 Read View 生成时机 核心影响
读已提交(RC) 每次执行快照读(普通 SELECT)时,都生成一个新的 Read View 每次读都会基于最新的活跃事务列表判断版本可见性,能看到其他事务刚提交的版本
可重复读(RR) 事务中第一次执行快照读时生成 Read View,后续所有快照读复用这个 Read View 整个事务内用同一个判断规则,多次读同一数据结果一致,不会看到其他事务提交的版本

补充:当前读(SELECT ... FOR UPDATE/INSERT/UPDATE)在两个隔离级别下行为完全一致------ 都是读取最新版本并加锁,不依赖 Read View 快照。

二、关键行为差异对比

基于 Read View 生成时机的不同,RC 和 RR 在 MVCC 层面会表现出 3 个核心差异,这也是面试高频考点:

对比维度 读已提交(RC) 可重复读(RR)
快照一致性 不保证可重复读:同一事务内多次快照读同一数据,结果可能不同 保证可重复读:同一事务内多次快照读,结果完全一致
版本可见性 能看到其他事务在两次快照读之间提交的新版本 看不到其他事务在本事务执行期间提交的任何版本
幻读问题 存在幻读:两次 SELECT 可能返回不同数量的行 解决幻读:InnoDB 通过 Next-Key Lock (行锁 + 间隙锁)配合 MVCC,避免幻读
Undo Log 清理 清理更及时:因为每次读都用新 Read View,旧版本很快不再被引用 清理较慢:因为事务复用 Read View,旧版本可能被长时间引用

三、实例验证:同一个场景下 RC 和 RR 的不同表现

用一个经典并发场景,直观对比两者差异。前置条件

  • user 表 id=1 的数据版本链:当前版本(102:王五) → 历史版本1(101:李四) → 历史版本2(0:张三)
  • 事务 102 未提交时,开启事务 103 执行快照读。

场景流程

时间 事务 102(未提交) 事务 103(隔离级别 RC) 事务 103(隔离级别 RR)
T1 UPDATE user SET name='王五' WHERE id=1;(未提交) 开始事务 开始事务
T2 - SELECT name FROM user WHERE id=1;(快照读) SELECT name FROM user WHERE id=1;(快照读)
T3 提交事务 - -
T4 - SELECT name FROM user WHERE id=1;(快照读) SELECT name FROM user WHERE id=1;(快照读)

结果分析

  1. T2 时刻(事务 102 未提交)

    • 无论 RC/RR,生成的 Read View 中 m_ids 都包含 102(活跃事务)。
    • 判断当前版本(102: 王五):DB_TRX_ID=102m_ids 中 → 不可见。
    • 遍历版本链,找到历史版本 1(101: 李四):DB_TRX_ID=101 < min_trx_id → 可见。
    • RC/RR 结果一致 :返回 李四
  2. T4 时刻(事务 102 已提交)

    • RC 隔离级别 :第二次 SELECT生成新的 Read View ,此时 m_ids 已不包含 102(事务 102 已提交)。判断当前版本(102: 王五):DB_TRX_ID=102 不在 m_ids 中 → 可见。结果 :返回 王五(两次读结果不同,不保证可重复读)。
    • RR 隔离级别 :第二次 SELECT 复用 T2 生成的 Read Viewm_ids 仍包含 102。判断当前版本(102: 王五):DB_TRX_ID=102m_ids 中 → 不可见。继续遍历版本链,返回 李四(两次读结果相同,保证可重复读)。

四、总结:RC 和 RR 的 MVCC 差异本质

本质 读已提交(RC) 可重复读(RR)
核心区别 每次快照读刷新 Read View 事务内复用 Read View
一致性 语句级一致性(每次读独立) 事务级一致性(全程一致)
适用场景 对一致性要求低、追求高并发的业务(如电商商品列表) 对一致性要求高的业务(如金融转账、订单支付)
相关推荐
朱峥嵘(朱髯)18 小时前
数据库如何根据估计 NDV,以及通过分区 NDV 推导全局 NDV
数据库·算法
luoluoal18 小时前
基于python的二维码生成算法研究和实现(源码+文档)
python·mysql·django·毕业设计·源码
高溪流18 小时前
2.Mysql相关概念 及 数据库操作
数据库·mysql
Summer_Uncle18 小时前
【QT学习】qt项目使用MySQL数据库
数据库·qt·学习
施嘉伟18 小时前
Oracle 10046 Trace 硬核指南:SQL 慢在哪,从底层拉出来
数据库·sql·oracle
_ziva_19 小时前
MAC-SQL 多智能体协作框架解析
数据库·oracle
最贪吃的虎19 小时前
Redis其实并不是线程安全的
java·开发语言·数据库·redis·后端·缓存·lua
代码不停19 小时前
MySQL事务
android·数据库·mysql
山峰哥19 小时前
数据库工程与SQL调优实战:从原理到案例的深度解析
java·数据库·sql·oracle·性能优化·编辑器