当前读与快照读

MySQL 使用 MVCC 机制,可以读取之前版本数据。这些旧版本记录不会且也无法再去修改,就像快照一样。所以我们将这种查询称为快照读
当然并不是所有查询都是快照读,select …. for update/ in share mode 这类加锁查询只会查询当前记录最新版本数据。我们将这种查询称为当前读

问题分析

image.png

事务隔离级别为 RR,t2,t3 时刻两个事务由于查询语句,分别建立了一致性视图。
t4 时刻,由于事务 1 使用 select.. for update 为 id=1 这一行上了一把锁,然后获取到最新结果。而 t5 时刻,由于该行已被上锁,事务 2 必须等待事务 1 释放锁才能继续执行。
t6 时刻根据一致性视图,不能读取到其他事务提交的版本,所以数据没变。t8 时刻余额扣减 100,t9 时刻提交事务。
此时最新版本记录为 id=1 balance=900
由于事务 1 事务已提交,行锁被释放,t5 成功获取到锁。由于 t5 是当前读,所以查询的结果为最新版本数据(1,900)。
重点来了,当前这条记录的最新版本数据为 (1,900),但是最新版本事务 id,却是事务 2 创建之后未提交的事务,位于活跃事务数组中。所以最新记录版本对于事务 2 是不可见的。
没办法只能根据 undolog 去读取上一版本记录 (1,1000) ,这个版本记录刚好对于事务 2 可见,所以 t11 的记录为 (1,1000)
而当我们将事务隔离等级修改成 RC,每次都会重新生成一致性视图。所以 t11 时刻重新生成了一致性视图,这时候事务 1 已提交,当前最新版本的记录对于事务 2 可见,所以 t11 的结果将会变为 (1,900)