快照读在执行的时候,到底读取undo log版本链的哪个历史记录,就是由readview来决定的

readview(读视图)是快照读SQL执行时MVCC提取数据的依据(就是依据于下面四个字段),记录并维护系统当前活跃的事务(未提交的)id。 readview包含了四个核心字段,如下:

字段含义
m_ids是一个集合,保存的是当前活跃的事务的id
min_trx_id最小活跃事务的id
max_trx_id预分配事务的id,不是最大事务id,是下一个事务id。当前最大事务id+1(因为事务id是自增的)
creator_trx_idreadview创建者的事务id,也就是当前事务id

 

工作流程如下。先假设有一个db_trx_id,代表的是当前事务的id,然后进行下面的比对(有4个比对)及比对通过后对应的结果(我用中括号围起来的), 比对的过程就是版本链数据访问规则:

1、db_trx_id == creator_trx_id ? 【可以访问该版本。原因: 可以说明数据是当前这个事务更改的】

2、db_trx_id < min_trx_id ? 【可以访问该版本。原因: 可以说明数据已经提交】

3、db_trx_id > max_trx_id ? 【不可以访问该版本。原因:可以说明该事务是在readview生成后才开启的】

4、db_min_trx_id <= trx_id <= max_trx_id ? 【如果trx_id不在m_ids中是可以访问该版本的。原因: 可以说明数据已经提交】

 

不同的隔离级别,生成readview的时机也就不同:

1、read committed隔离级别(InnoDB引擎默认的隔离级别): 在事务中每一次执行快照读时都会生成readview 即每执行一次select语句就是一次快照读。把当前表的隐藏字段的db_trx_id值(由于有多个undo log版本链有多个版本,所以每个版本的db_trx_id值 不一样,db_trx_id值是递增的,先把最大db_trx_id值拿出来,跟上面4行进行比对,如果符合上面将的4个比对其中一种,那么当前select语句查到的 就是最大db_trx_id值对应的版本数据,如果不符合,那么就拿第二大db_trx_id值来跟上面4行进行比对,还不符合就拿第三大db_trx_id值来跟上面4 行进行比对,总会有db_trx_id值是符合的,如果符合,则当前db_trx_id值对应的版本就是select语句查到的数据

2、repeatable read隔离级别: 仅在事务中第一次执行快照读时生成readview,后续复用该readview 跟上面的RC隔离级别的过程一样。唯一的区别是这里不同版本的readview是相同的