不可重复读(RC)和可重复读(RR) 底层逻辑是什么?

“不可重复读”和“可重复读”的底层含义就是一句话:

“同一事务里先后两条 SELECT 生成的 ReadView 是不是同一个?”

1. 可重复读(RR)

 

事务里第一次 SELECT 时生成 ReadView,整个事务不再重新生成。

 

后一条 SELECT 仍然用同一张快照,所以只要别人在那之后提交,你也看不见 → 多次读结果一样 → “可重复读”。

2. 不可重复读(RC)

 

每条 SELECT 开始都重新生成 ReadView,快照点永远取“语句开始那一刻最新已提交版本”。

 

如果别的事务在这两条 SELECT 之间提交,第二次就能看到新数据 → 两次结果不一样 → “不可重复读”。

底层只有这一个差别:

ReadView 的生命周期 = 事务级(RR) vs 语句级(RC);

上层现象就是“能不能重复读到相同行”




在 MySQL(InnoDB)里,“当前读” 与 “快照读” 是两种读取数据时所使用的版本/加锁策略,直接决定了:

 

你能不能读到别的事务刚提交的新数据

 

你读的时候要不要加锁、会不锁别人

下面按“定义 → 实现机制 → 语句表现 → 可见性 → 锁冲突 → 适用场景”六层给你拆开。

1. 定义一句话

快照读(consistent read):读取事务启动时那一刻已经存在的快照,不加锁、不阻塞、不冲突, repeatable-read 级别下保证“可重复读”。

 

当前读(locking read):读取最新已提交版本,并对返回记录加锁(S/X),阻塞其他事务的并发写,保证“读到的就是此刻最新且别人改不了”。

2. 实现机制

快照读:利用 InnoDB MVCC(隐藏列 trx_id + ReadView),只在第一次 SELECT 时生成 ReadView,之后复用,读到的是“历史版本”。

当前读:直接走最新版本链,同时加记录锁 / 间隙锁(lock_mode=X or S),写入前必须获得锁,因而也叫“锁定读”。

3. SQL 语句表现

attachments-2025-12-40jKyjuW694ca20e80cdc,png

4. 可见性差异

会话 1(RR 级别)

BEGIN;

SELECT money FROM account WHERE id=1;   -- 100  快照读

-- 此时会话 2 把 money 改成 200 并提交

SELECT money FROM account WHERE id=1;   -- 100  快照读,依旧 100

SELECT money FROM account WHERE id=1 FOR UPDATE; -- 200 当前读,读到最新


5. 锁冲突演示

attachments-2025-12-VJIR7s7Q694ca21a46e72,png

6. 典型场景选择

快照读:报表、只读查询、可重复读业务逻辑,不想被阻塞也不想阻塞别人。

 

当前读:

– 先读后写(“读-改-写”)必须保证读最新,否则会出现“丢失更新”;

– 需要显式加锁让后续操作排他;

– 串行化隔离级别下所有 SELECT 也退化为当前读。

一句话总结

快照读 = 看历史照片,不加锁;

当前读 = 看现场直播,加锁防改。

在 RR 级别下,普通 SELECT 用快照,SELECT … FOR UPDATE/UPDATE/DELETE 用当前读,两者结合才同时实现“高性能+一致性”。

请先 登录 后评论
  • 0 关注
  • 0 收藏,17 浏览
  • shitian 提出于 2025-12-25 10:26

相似问题