• 事务总能够读取到,自己写入(update /insert /delete)的行记录
• RC下,快照读总是能读到最新的行数据快照,当然,必须是已提交事务写入的
• RR下,某个事务首次read记录的时间为T,未来不会读取到T时间之后已提交事务写入的记录,以保证连续相同的read读到相同的结果集
### InnoDB 快照读在RR和RC下的差异详解
#### 概述
在数据库管理系统中,事务隔离级别是确保数据一致性和并发控制的关键组成部分。MySQL的InnoDB存储引擎使用多版本并发控制(MVCC)机制来支持四种不同的事务隔离级别:读未提交(Read Uncommitted)、读已提交(Read Committed,简称RC)、可重复读(Repeatable Read,简称RR)和串行化(Serializable)。本文将重点探讨快照读在RR和RC两种隔离级别下的行为差异,并通过具体的案例来说明这些差异。
#### 快照读(Snapshot Read)
快照读是指在不加锁的情况下,读取数据行的历史版本,以此来实现一致性读。这种读取方式提高了系统的并发性,尤其是在高并发场景下,避免了不必要的锁定操作,从而提升了性能。
#### 读已提交(RC)
读已提交是一种常见的事务隔离级别,其主要特性如下:
- **解决“读脏”问题**:确保事务只能读取到其他事务已提交的数据。这意味着如果一个事务尝试读取另一事务尚未提交的数据,则会等到该数据被提交后才能读取。
- **存在“读幻影行”问题**:同一个事务中,两次执行相同的SELECT语句可能会得到不同的结果集。这是因为其他事务可能在两次读取之间插入了新行,而这些新行在第一次读取时并不存在。
#### 可重复读(RR)
可重复读提供了一种更严格的事务隔离级别,其特点包括:
- **解决“读脏”和“读幻影行”问题**:不仅确保事务只能读取到其他事务已提交的数据,而且还保证了事务在其生命周期内多次执行相同的SELECT语句时得到相同的结果集。
- **保持结果集不变**:一旦事务开始了它的第一次读取,那么在未来所有的读取操作中,都不会读取到这个第一次读取之后其他事务提交的数据。
#### 案例分析
接下来,我们将通过几个具体的案例来深入理解RR和RC在快照读方面的差异。
### 案例1:RR隔离级别下快照读的行为
假设有一个InnoDB表`t`,包含以下记录:
- 1, shenjian
- 2, zhangsan
- 3, lisi
事务A和事务B按以下顺序执行:
1. A: start transaction;
2. B: start transaction;
3. A: select * from t; (A2)
4. B: insert into t values (4, wangwu);
5. A: select * from t; (A3)
6. B: commit;
7. A: select * from t; (A4)
**提问1:** 假设事务的隔离级别是RR,事务A中的三次查询A2、A3、A4分别读到什么结果集?
- **回答:**
- **A2** 读到的结果集肯定是 {1, 2, 3},这是事务A的第一个read,假设为时间T。
- **A3** 读到的结果集也是 {1, 2, 3},因为B事务还未提交。
- **A4** 读到的结果集还是 {1, 2, 3},因为事务B是在时间T之后提交的,A4需要读取到与A2相同的结果集。
### 案例2:RC隔离级别下快照读的行为
使用同样的表`t`和事务执行顺序,但改变事务的隔离级别为RC。
**提问2:** 假设事务的隔离级别是RC,A2、A3、A4的结果集又是什么呢?
- **回答:**
- **A2** 读到的结果集是 {1, 2, 3}。
- **A3** 读到的结果集也是 {1, 2, 3},因为B事务还未提交。
- **A4** 读到的结果集是 {1, 2, 3, 4},因为事务B已经提交。
### 案例3:RR隔离级别下快照读的不同开始时间
假设事务A和B的开始时间稍有不同,但执行顺序相同。
**提问3:** 假设事务的隔离级别是RR,事务A中的三次查询A2、A3、A4分别读到什么结果集?
**提问4:** 假设事务的隔离级别是RC,A2、A3、A4的结果集又是什么呢?
- **回答:**
- 在RR下,事务的开始时间不会影响快照读的结果,因此结果集与案例1相同。
- 在RC下,结果集也与案例2相同。
### 案例4:RR隔离级别下快照读的另一个开始时间
再次更改事务A和B的开始时间,但执行顺序相同。
**提问5:** 假设事务的隔离级别是RR,事务A中的A2查询,结果集是什么?
**提问6:** 假设事务的隔离级别是RC,A2的结果集又是什么呢?
- **回答:**
- 在RR下,A2是事务A的第一个read,假设为时间T,它能读取到T之前提交事务写入的数据行,故结果集为 {1, 2, 3, 4}。
- 在RC下,结果集一定是 {1, 2, 3, 4}。
### 结论
通过上述案例分析可以看出,快照读在RR和RC两种隔离级别下的行为有明显差异:
- **RR**:确保事务在其生命周期内的多次读取操作中获得相同的结果集,即事务A的第一次读取时间点T决定了后续所有读取操作中所能读取的数据范围。
- **RC**:允许事务在其生命周期内读取到其他事务提交的新数据,导致两次相同的读取操作可能返回不同的结果集。
了解这些差异对于正确选择合适的事务隔离级别以及优化数据库应用的设计至关重要。