事务的启动时间是啥时候?
什么是一致性读视图?
一致性读视图是InnoDB在实现MVCC用到的视图,用于读提交(RC)和可重复度(RR)隔离级别的实现。
一致性视图没有物理结构,主要是在事务执行期间用来定义该事物可以看到什么数据。
什么是row trx_id?
事务在正式启动的时候我们会创建一致性视图,该一致性视图是基于整个库的。该一致性视图不会拷贝整个数据库的数据(因为拷贝数据是不现实的)。
InnodDB的每个事务都有一个唯一的事务ID,叫做transaction id,该ID在事务开始的时候向InnoDB申请,并且按照申请顺序严格递增。
每行数据都会有多个版本,每次事务更新数据的时候都会生成一个新的数据版本,并且把transaction id赋值给这个数据版本的事务id,称为row trx_id。
如上图所示,是一行记录被多个事务更新后的状态,该行记录的最新版本是有由transaction id为25的事务更新的,因此row trx_id也为25。
U3、U2、U1代表的是undo log,V1、V2、V3在物理上并不真实存在,而是在需要的时候通过V4配合undo log计算获得。
如何构建一致性读视图?
InnoDB会为每个事务构造一个数组,该数组用来保存事务启动瞬间当前正在活跃(启动还未提交)的所有事务ID。
数组里面事务ID的最小值为低水位,当前系统里面已经创建过的事务ID的最大值加1位高水位。该视图数组和高水位就组成了当前事务的一致性视图。
对于当前事务的启动瞬间,一个数据版本的row trx_id会有以下几种可能:
上述是代码逻辑的,我们可以简化一下,一个数据版本,对于一个事务视图来说,除了自己的更新总是可见以为,有以下几种情况:
update逻辑和select逻辑的不同
假设id=1的k初始值为1,隔离级别为可重复读,大家可以试着分析以上三个事务的结果:
根据我们上面将的多版本控制和一致性视图,事务A很容易得出1,事务C很容易得出2,但是如果按照上述分析,事务B的结果会和预想的不太一致,这是因为事务B中出现了update这行记录,update和单纯的select将会有些许不同。
update在更新数据时候不能在历史版本上进行更新的,也就是说事务B是在k=2的基础上进行更新,此时就需要用到一条规则:更新数据都是先读后写,并且这个读为当前读。
除了update语句以为,select如果加锁也是当前读,如下:
-- 加读锁
select k from t where id = 1 lock in share mode;
-- 加写锁
select k from t where id = 1 for update;
我们对之前的事务C做些改造,如上图,改造完成以后会发生如下情况:
事务如何实现MVCC?