MVCC实现原理

663 阅读2分钟

当前读:读取的都是最新版本,会对读取的内容进行加锁。
快照读:读到的不一定是最新的版本,不加锁的非阻塞读,隔离级别不能是串行化,不然会退化成当前读。基于多版本并发控制(MVCC)实现的。

MVCC

MVCC的全称是多版本并发控制,它在具体的每一行中都添加了三个隐藏字段。

图片.png

  1. DB_ROW_ID:隐藏的自增ID,当数据库表没有指定主键的时候,会自动生成。
  2. DB_TRX_ID:记录插入或者更新该行数据的最后一个事务ID。
  3. DB_ROLL_PTR:回滚指针,指向该行的上一个记录。

所以当我们去select数据的时候,我们需要比较当前事务ID和数据表中最后一个更新数据的事务ID,若我们当前事务是在上一次提交事务之后,毫无疑问我们可以读到当前数据,否则则读不到当前的数据。那么我们要怎么读到我们当前事务读得到的数据呢?

Read View(读视图)

什么是读视图呢?其实事务执行快照读的时候,它会去维护一个与当前事务相关的一个表,去记录维护当前活跃的事务ID。

Read View可以简单理解为有三个属性:

  1. trx_list: 一个存放读视图生成时正在活跃的事务ID
  2. up_limit_id: 记录列表中最小的事务ID
  3. low_limit_id: 已经出现过的事务ID的下一个ID,即最大的+1

可见性: 说白了,这个读视图的作用就是为了让我们能够得到当前事务该读到什么版本的数据,它遵循以下的算法:

  • 首先比较数据行中的DB_TRX_ID是否小于up_limit_id,如果小于,则证明这行数据是在这些活跃事务之前就已经存在的了,那么当前事务对这行数据就是可见的。
  • 否则,判断DB_TRX_ID是否大于low_limit_id,如果大于,则证明这行数据是在读视图的生成后被修改了,则对当前事务是不可见的。则会通过DB_ROLL_PTR回滚指针找到上一次的数据,然后重复刚开始的判断。
  • 如果小于low_limit_id,则去正在活跃的事务列表中查找是否存在DB_TRX_ID,如果存在,则证明数据还未commit,所以当前数据对当前事务是不可见的,如果不在,则证明这个事务刚好在读视图创建之前提交的,此时是可见的。