• mvcc机制中的快照读和当前读


    什么是MVCC?

    MCVV(Multiversion Concurrency Control),多版本并发控制是InnoDB引擎处理读写冲突的手段,目的是用来提高数据库并发场景下的吞吐性能。
    不同的事务在并发过程中,SELECT操作可以不加锁,而是通过MVCC机制来指定读取版本,通过一些手段来保证读取的数据符合事务隔离级别,从而解决并发场景下的读写冲突

    版本链

    又称事务链,每次修改数据的时候,都会记录一条undoLog日志,日志中记录数据每一次的变化,并且通过数据中的两个隐藏列,trx_id(事务id)用标记每一条数据对应的事务id,roll_pointer(指针)用来串联版本链的指针。
    在这里插入图片描述

    ReadView

    阅读视图,可以理解为某一次读取的时候,根据不同的事务生成的数据快照,并且除了表中的数据,还有一下这些固定字段。
    m_ids:表示生成ReadView时,当前系统正在活跃的读写事务的事务Id列表。
    min_trx_id:表示生成ReadView时,当前系统中活跃的读写事务的最小事务Id。
    max_trx_id:表示生成ReadView时,当前时间戳InnoDB将在下一次分配的事务id。
    creator_trx_id:当前事务id。

    原理

    我们都知道,数据库的事务有四个隔离级别:读未提交(Read Uncommitted,简称RU)、读已提交(Read Committed,简称RC)、可重复读(Repeatable Read,简称RR)、串行化(Serializable)。
    只有RC和RR才跟MVCC机制有关,因为RU会直接返回记录上的最新值,而Serializable是每一次操作都要加锁。

    RC和RR的事务隔离就是通过版本链来控制的,核心逻辑就是判断版本链中的那个版本是当前事务可见可处理的

    举个例子,当前有个数据的初始值是 name=“刘德华”

    下面是事务时间表,有这样5个事务

    时间tx_100tx_200tx_300tx_400tx_500
    T1begin;
    T2begin;begin;
    T3update user set name = “古天乐” where id = 1
    T4select * from user where id = 1begin;
    T5commit;update user set name = “刘青云” where id = 1
    T6select * from user where id = 1select * from user where id = 1begin;
    T7commit;
    T8select * from user where id = 1select * from user where id = 1

    当在T4时间点的时候,版本链如下:

    idnametrx_idroll_pointer
    1刘德华0null
    1古天乐100roll_pointer(指向上一个版本)

    RC隔离级别

    当在读已提交(Read Committed)隔离级别的时候,每一次读取都会生成一个新的ReadView。

    当处于T4时间点,由于tx_100事务未提交,tx_200事务未操作,事务 tx_300 查询出的数据就是 name=“刘德华”。

    idnametrx_idroll_pointer
    1刘德华0null
    1古天乐100roll_pointer(指向上一个版本)

    当处于T6时间点,tx_100事务已提交,tx_200事务未提交,那么tx_300事务查询出来的数据就是name=“古天乐”。tx_400事务也是一样。

    idnametrx_idroll_pointer
    1刘德华0null
    1古天乐100roll_pointer(指向上一个版本)
    1刘青云200roll_pointer(指向上一个版本)

    当处于T8时间点,tx_100、tx_200事务都已提交,所以tx_300、tx_500事务查询到的数据都是name=“刘青云”。

    idnametrx_idroll_pointer
    1刘德华0null
    1古天乐100roll_pointer(指向上一个版本)
    1刘青云200roll_pointer(指向上一个版本)

    有没有发现一个问题,在tx_300事务中,虽然是同一个事务下,但是每次查询的数据都不一样,这就是出现了不可重复读的现象。

    RR隔离级别

    当处于可重复读(Repeatable Read)隔离级别的时候,与RC最大的不同就是同一个读取事务,只有一个ReadView。

    事务tx_300查询了3次,第一次查询的时候是在T4时间点,tx_100事务还未提交数据,所以生成了一个快照ReadView1,name=“刘德华”。

    T6时间点事务tx_300第二次查询的时候不会生成新的快照,依旧获取的是ReadView1,name=“刘德华”。 而此时查询的事务tx_400,则会生成快照ReadView2,name=“古天乐”。

    T8时间点的时候,事务tx_300第三次查询依旧不会生成新的快照,获取的数据还是ReadView1,name=“刘德华”。 此时查询事务tx_500,则会生成新的快照ReadView3,name=“刘青云”。

    MVCC机制,就是通过版本链来控制每一个事务读取的版本,从而实现事务的隔离级别。关键是要理解,如何通过控制ReadView的生成,来实现不同的事务隔离级别。

    当前读

    读取的是最新版本,并且对数据加锁,阻塞其他操作修改记录。
    比如select… update,update,delete,insert这类操作都是当前读

    快照读

    只有select单纯的读取操作,会在读取的时候生成ReadView快照数据。
    并且RC隔离级别下,会在每次select操作的时候都生成一个ReadView快照。
    而在RR隔离级别下,同一个事务中只会在第一次select操作的时候生成ReadView快照,避免同一个事务多次读取的数据不一样。

  • 相关阅读:
    视频讲解|1033含sop的配电网重构(含风光可多时段拓展)
    程序员的七夕怎么过?不会是写代码吧
    #力扣:344. 反转字符串@FDDLC
    正则表达式re模块的使用教程『更新中』
    黑苹果修改intel hd3000核显显存大小.2022-11-29
    面试题常考:LRU缓存
    全网最全Python系列教程(非常详细)---数值篇讲解(学Python入门必收藏)
    pytorch梯度累积
    selenium 下载文件取消安全下载的方法
    【洛谷 P1328】[NOIP2014 提高组] 生活大爆炸版石头剪刀布 题解(模拟+向量)
  • 原文地址:https://blog.csdn.net/weixin_41011482/article/details/126152449