转载:《InnoDB,快照读,在RR和RC下有何差异?》


结论


为了保证文章知识体系的完整性,先简单解释下快照读读提交可重复读


快照读(Snapshot Read


MySQL 数据库,InnoDB 存储引擎,为了提高并发,使用 MVCC 机制,在并发事务时,通过读取数据行的历史数据版本,不加锁,来提高并发的一种不加锁一致性读(Consistent Nonlocking Read)。


读提交(Read Committed


可重复读(Repeated Read)



在读提交(RC),可重复读(RR)两个不同的事务的隔离级别下,快照读有什么不同呢?


先说结论:



可以看到:



示例


InnoDB 表:t(id PK, name); 


表中有三条记录:


1, shenjian
2, zhangsan
3, lisi


示例1


两个并发事务A,B执行的时间序列如下(A先于B开始,B先于A结束):


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,事务A中的三次查询,A2, A3, A4分别读到什么结果集?


回答:RR下


  1. A2读到的结果集肯定是 {1, 2, 3},这是事务A的第一个 read,假设为时间T;
  2. A3读到的结果集也是 {1, 2, 3},因为B还没有提交;
  3. A4读到的结果集还是 {1, 2, 3},因为事务B是在时间T之后提交的,A4得读到和A2一样的记录;


提问2:假设事务的隔离级别是读提交RC,A2, A3, A4又分别读到什么结果集呢?


回答:RC下


  1. A2读到的结果集是 {1, 2, 3};
  2. A3读到的结果集也是 {1, 2, 3},因为B还没有提交;
  3. A4读到的结果集还是 {1, 2, 3, 4},因为事务B已经提交;


示例2


仍然是上面的两个事务,只是A和B开始时间稍有不同(B先于A开始,B先于A结束):


                 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:假设事务的隔离级别是可重复读RR,事务A中的三次查询,A2, A3, A4分别读到什么结果集?


提问4:假设事务的隔离级别是读提交RC,A2, A3, A4的结果集又是什么呢?


回答事务的开始时间不一样,不会影响“快照读”的结果,所以结果集和示例1一样。


示例3


仍然是并发的事务A与B(A先于B开始,B先于A结束):


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


提问5:假设事务的隔离级别是可重复读RR,事务A中的A2查询,结果集是什么?


提问6:假设事务的隔离级别是读提交RC,A2的结果集又是什么呢?


回答:



示例4


事务开始的时间再换一下(B先于A开始,B先于A结束):


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


提问7:假设事务的隔离级别是可重复读RR,事务A中的A2查询,结果集是什么?


提问8:假设事务的隔离级别是读提交RC,A2的结果集又是什么呢?


回答事务的开始时间不一样,不会影响“快照读”的结果,所以结果集和示例3一样。


啰嗦说了这么多,用昨天一位网友“山峰”同学的话总结:



mm_reward_qrcode_1574408256457.png