mysql mvvc

mysql中,每一行数据,除了本身的数据,还维护着其他信息,其中包括:

  1. 一个隐藏id
  2. 事务id
  3. 回滚指针。
    其中隐藏id的选择规则如下:
  • 如果有主键id, 则是主键id
  • 如果有唯一键,则是唯一键
  • 如果都没有,则mysql生成一个隐藏id

事务id是顺序递增的,每新增一个事务,事务id就加1;同时,将(update|insert)操作的sql语句记录在undolog中,而回滚指针则指向上一个事务的地址。便于当前事务失败的时候,结合undolog日志,回滚到之前的状态。
但是,当并发的时候,当前事务之前的事务都是历史版本;当存在多个历史版本的时候,我们读的时候要读哪个历史版本呢?这就会设计到一个可见性算法,来计算当前事务读取的是哪一个版本的历史数据。这个可见性算法就是read view:读视图。

read view

当进行快照读的时候会生成一个事务id的列表,来保存不同的信息,这个列表就是readview;通过这些信息来做可见性的判断。这些信息包括:

  • list:生成readview的时候活跃的id
  • up_limit_id:当前活跃id的最小值
  • low_limit_id:尚未分配的下一个事务id

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

  • RC(读已提交隔离级别)下:每次快照读的时候生成新的readview
  • RR(可重复读隔离级别)下:readview第一次执行快照读的时候会生成,之后都是这个版本的。

其判断规则为:

  • 判断被访问版本的 trx_id 属性值是否小于 up_limit_id,如果小于,表明生成该版本的事务在生成 ReadView 前已经提交,所以该版本可以被当前事务访问。
  • 判断被访问版本的 trx_id 属性值是否大于 lower_limit_id ,如果大于,表明生成该版本的事务在生成 ReadView 后才生成,所以该版本不可以被当前事务访问。
  • 判断被访问版本的 trx_id 属性值是否在list 列表中,如果在,说明创建 ReadView 时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问。

例如下方事务列表:

事务1 事务2 事务3 事务4
begin begin begin begin
nothing todo nothing todo nothing todo update; commint;
select(读视图) -

当前情况下:
undolog中保存的历史版本只有一个,就是事务4.
list: 1,2,3 (当前获取的事务列表)
up_limit_id:1 (当前活跃的最小事务id)
low_limit_id:5(下一个分配的事务id)

于是可以得出当前行的事务ID(也就是trx_id)是4,根据上方的条件判断:RC隔离级别是可以堵到事务4提交的数据,而RR隔离级别是读取不到的。


mysql mvvc
https://randzz.cn/bdb9d4f1f954/mysql-mvvc/
作者
Ezreal Rao
发布于
2021年9月8日
许可协议