这下弄懂什么是快照读和什么是当前读了

锁模块之快照读和当前读

InnoDB可重复读隔离级别下如何避免幻读?

  • 表象:快照读(非阻塞读) --伪MVCC
  • 内在:next-key锁(行锁+gap锁)

回答这个问题前我们先要了解下什么是快照读、什么是当前读。

当前读:select...lock in share mode; select...for update;
当前读:updateinsertdelete
快照读:不加锁的非阻塞读,select

演示一下什么是快照读、什么是当前读

打开两个会话,确保一下两个会话的事务隔离级别都在RR级别下

这下弄懂什么是快照读和什么是当前读了_第1张图片

这下弄懂什么是快照读和什么是当前读了_第2张图片

这下弄懂什么是快照读和什么是当前读了_第3张图片

快照读读到的版本数据取决于快照读先出现的地方的时机,我们来看下开启事务后先不执行快照读直接进行更新操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FKSOFBQO-1594698883837)(C:\Users\14222\AppData\Roaming\Typora\typora-user-images\image-20200714095058653.png)]

以上演示的是RR级别下的快照读和当前读,快照读的版本取决于快照读发生的时机。而在RC级别下,快照读读取的是当前最新的数据。

RC、RR级别下的InnoDB的非阻塞读如何实现

我们在存储一条数据时,除了我们能看到的字段,其实mysql还给我们添加了许多的隐藏字段,比如与我们题目有关的字段:DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID字段,看他们的名字就能够大致知道是什么意思。

  • DB_TRX_ID:事务ID,每开启一个新事务,当前的事务id就自动加一,事务id越大,表明当前启动事务时间离当前时间越近。
  • DB_ROLL_PTR:回滚指针,比如当前事务去更新一条数据的时候,这条数据的回滚指针会指向undo log里最大的事务id的地址,也就是最新的undo日志
    • undo log是在一个事务中每进行一次增删改操作就形成的一条undo日志,它是用于在事务回滚是回到事务开启之前的版本。它也分为insert undo log和update undo log
  • DB_ROW_ID:行号,新行插入,对应行号,如果一个InnoDB表中的字段没有唯一索引和主键索引,InnoDB会自动生成隐藏自增主键字段,也就是这个字段。

实现快照读除了用到上面的三个隐藏字段和undo日志,还需要一个read view,当我们去执行快照读的时候,针对我们读的数据会创建一个read view来决定我们读到的是哪个版本的数据,有可能是最新版本的数据,也有可能是undo日志里的某个版本的数据。read view遵循一个可见性算法,主要是将要修改的数据的DB_TRX_ID取出来与系统其它活跃事务ID作比较,如果大于等于这些ID,就通过DB_ROLL_PTR指针去取出undolog中的数据直到小于这些活跃事务ID为止,这样就能保证获取到的数据是当前事务可见的最稳定的版本。

在RR级别下,session在开启事务后的第一条快照读会创建一个快照,也就是read view,将当前系统中活跃的其他事务记录起来,此后,再调用这个read view,在RC级别下,在开启事务后每次调用快照读的情况下都会创建一个快照,这就是之前RC级别下快照读每次都能看到其他事务进行的最新的增删改,而在RR级别下如果首次使用快照读是在别的事务进行增删改之前调用的,此后即便别的事务做了增删改还是得不到最新数据的原因。所以在RR级别下,首次进行快照读的时机是很重要的。

为什么是伪MVCC

MVCC就是多版本并发控制,也就是非阻塞读,上面提到的MVCC为什么是伪MVCC呢?因为这里的undo log是串行化的不属于多个版本共存的例子,所以不是MVCC。

你可能感兴趣的:(mysql,数据库)