Mysql之MVCC

InnoDB 里面每个事务有一个唯一的事务 ID,叫作 transaction id。它是在事务开始的时候向 InnoDB 的事务系统申请的,是按申请顺序严格递增的。

每行数据有多个版本,每次事务更新数据的时候,都会生成一个新的数据版本,并且把 transaction id 赋值给这个数据版本的事务 ID,记为 row trx_id。同时,旧的数据版本要保留,并且在新的数据版本中,可以直接拿到它。

Mysql之MVCC

上图中三个虚线箭头,即U1、U2、U3就是 undo log,而V1、V2、V3 并不是物理上真实存在的,而是每次需要的时候根据当前版本和 undo log 计算出来的

快照是基于整库的,如何构建的?

按照可重复读的定义,一个事务启动的时候,能够看到所有已经提交的事务结果,但是之后的事务执行期间,其他事务的更新对它不可见。

Mysql之MVCC

在实现上, InnoDB 为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在“活跃”的所有事务 ID,即启动了但还没提交的事务ID,对应上图中黄色部分。这个数组对应两个概念:

  • 低水位:数组里面事务ID最小值
  • 高水位:当前系统里面已经创建过的事务 ID 的最大值加 1 记为高水位

由视图数组和高水位,组成了当前事务的一致性视图(read-view),而数据版本的可见性规则,就是基于数据的 row trx_id 和这个一致性视图的对比结果得到的,如下所示:

  • 如果落在绿色部分,即小于低水位,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的;
  • 如果落在红色部分,即大于等于高水位,表示这个版本是由将来启动的事务生成的,是肯定不可见的;
  • 如果落在黄色部分,那就包括两种情况:
    • 若 row trx_id 在数组中,表示这个版本是由还没提交的事务生成的,不可见
    • 若 row trx_id 不在数组中,表示这个版本是已经提交了的事务生成的,可见
-- 假设存在事务T1,T2,T4,T7,T8,T9,其中T2,T4,T8活跃状态,此刻启动事务A

-- 事务A的视图数组viewA如下
viewA = [T2,T4,T8]

-- 低水位
lowLevel = T2
    
-- 高水位
highLevel = T9 + 1
    
-- T1:T1 < T2,即处于绿色部分,对于事务A可见
-- T11:T11 > T10,即处于红色部分,对于事务A不可见
-- T4:T4 > T2 && T4 < T10,即处于黄色部分,且存在viewA中,说明未提交不可见
-- T7:T7 > T2 && T7 < T10,即处于黄色部分,但不存在viewA中,说明已提交可见

MVCC只在读已提交和可重复读两个隔离级别下工作,两者的差异在于:

  • 读已提交每次读取都会创建一个新的read-view
  • 可重复读在同一个事务*享同一个read-view

Mysql之MVCC

上一篇:第3章 SQL语句


下一篇:postman接口自动化测试之利用node.js和xmysql连接、操作数据库