找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

549

积分

0

好友

69

主题
发表于 4 天前 | 查看: 13| 回复: 0

在探讨数据库并发控制时,我们常会接触到“快照读”、“读提交(RC)”、“可重复读(RR)”这几个核心概念。理解它们在 MySQL InnoDB引擎下的行为差异,对于设计高并发应用至关重要。

核心概念解析

快照读 (Snapshot Read)
MySQL 数据库,InnoDB存储引擎,为了提高并发,使用了MVCC(多版本并发控制)机制。在并发事务环境下,通过读取数据行的历史数据版本,来实现一种不加锁的一致性读(Consistent Nonlocking Read),这就是快照读。

读提交 (Read Committed, RC)

  1. 这是数据库事务隔离级别的一种。
  2. 它解决了“读脏”(Dirty Read)问题,保证事务读取到的数据行都是其他已提交事务写入的。
  3. 但它可能存在“不可重复读”或“幻读”问题,即同一个事务内,连续执行相同的查询可能读到不同的结果集。

可重复读 (Repeated Read, RR)

  1. 同样是事务隔离级别的一种。
  2. 它不仅解决了“读脏”问题,还致力于解决“不可重复读”问题,保证在同一个事务里,连续相同的查询总能读到相同的结果集。

那么,在读提交(RC)可重复读(RR)这两种不同的事务隔离级别下,快照读的行为究竟有什么不同呢?

核心结论

我们先明确结论:

  1. 事务总是能够读取到自己写入(通过 UPDATEINSERTDELETE 操作)的行记录。
  2. RC 级别下,快照读总是能读取到最新的、已提交的行数据快照。
  3. RR 级别下,事务首次执行 SELECT 操作(快照读)的时间点记为 T。此后,在该事务内进行的任何快照读,都不会读取到时间点 T 之后才提交的事务所写入的记录,以此保证“可重复读”。

关键点:快照读的可见性与事务的开始时间无直接关系,而是与事务内首次读操作的时间点有关。同时,由于是不加锁读,其行为与锁的互斥关系也不大。

实例分析

我们通过一个InnoDB表 t(id PK, name) 来具体说明,表中初始有三条记录:

1, shenjian
2, zhangsan
3, lisi

案例 1

两个并发事务A和B按以下时间序执行(A先开始,B先结束):

A1: start transaction;
         B1: start transaction;
A2: select * from t;
         B2: insert into t values (4, wangwu);
A3: select * from t;
         B3: commit;
A4: select * from t;

提问1:在RR隔离级别下,A2、A3、A4分别读到什么结果集?
回答

  • A2是事务A的首次读,时间点为T,结果集为 {1, 2, 3}
  • A3发生在B提交前,读不到B未提交的数据,结果集仍为 {1, 2, 3}
  • A4发生在B提交后,但在RR下,事务A的读视图基于时间点T建立,T之后提交的事务B的修改不可见,因此结果集依然是 {1, 2, 3}

提问2:在RC隔离级别下,A2、A3、A4的结果集是什么?
回答

  • A2:{1, 2, 3}
  • A3:B未提交,所以仍是 {1, 2, 3}
  • A4:B已提交,RC下每次读都获取最新已提交快照,因此结果集为 {1, 2, 3, 4}

案例 2

调整事务开始顺序(B先开始,B先结束):

         B1: start transaction;
A1: start transaction;
A2: select * from t;
         B2: insert into t values (4, wangwu);
A3: select * from t;
         B3: commit;
A4: select * from t;

提问3 & 4:RR和RC下的结果分别是?
回答:事务的开始时间不同并不影响快照读的判定逻辑。因此,结果集与案例1完全相同。

案例 3

事务A和B(A先开始,B先结束),但A的读操作在B提交之后:

A1: start transaction;
         B1: start transaction;
         B2: insert into t values (4, wangwu);
         B3: commit;
A2: select * from t;

提问5:在RR下,A2的结果集?
回答:A2是事务A的首次读,时间点为T。此时事务B已在时间T之前提交,所以A2能读取到B已提交的修改,结果为 {1, 2, 3, 4}

提问6:在RC下,A2的结果集?
回答:RC下读取最新已提交数据,结果同样是 {1, 2, 3, 4}

案例 4

调整案例3的开始顺序(B先开始,B先结束):

         B1: start transaction;
A1: start transaction;
         B2: insert into t values (4, wangwu);
         B3: commit;
A2: select * from t;

提问7 & 8:RR和RC下的结果?
回答:同理,事务开始顺序不影响,结果集与案例3相同。

总结与原理

通过以上案例,我们可以清晰地看到差异并理解其背后的机制:

  1. RR(可重复读) 隔离级别下,事务在第一次执行快照读操作时,会创建一个Read View(读视图)。这个视图决定了该事务后续所有快照读能看到的数据版本。此后,即使其他事务提交了新的数据,只要该修改是在本事务的Read View创建之后提交的,就对当前事务不可见,从而保证了“可重复读”。
  2. RC(读提交) 隔离级别下,事务在每次执行快照读操作时,都会创建一个新的Read View。因此,每次读都能看到所有在该读操作之前已经提交的事务所做的修改,实现了“读提交”的语义。

理解“Read View”的创建时机,是掌握RC与RR下快照读差异的关键。这比单纯记住结论更重要,它能帮助你在复杂的并发场景中,准确推断数据可见性。




上一篇:认知模型重塑游戏未来:从信息爆炸到玩家行为与市场趋势的推演
下一篇:如何优化大流量电商APP订单列表?预请求、多实例架构与白屏治理实践
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-24 02:54 , Processed in 0.330179 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表