您的当前位置:首页正文

MVCC(多版本并发控制)原理

2024-11-07 来源:个人技术集锦

一、概念

        MVCC(Multi-Version Concurrency Control)是在mysql的innodb引擎中用来处理我们并发情况下操作数据时遇到的读写冲突问题的一种解决思想。

        MVCC的实现方式是通过Undo日志中的版本链和ReadView可读视图来实现的。MVCC就是在多个事务同时存在时,SELECT语句找寻到具体是版本链上的哪个版本,然后在找到的版本上返回其中所记录的数据的过程。

        解释版本链和可读视图之前,我们先要知道mysql会在数据表中默认添加三个隐藏列:

        DB_ROW_ID:行id,大小为 6 字节,若表没有主键,InnoDB 会自动生成一个隐藏主键,因此会出现这个列;
        DB_TRX_ID:事务ID,当有事务开启时会生成这样一个全局递增的id;
        DB_ROLL_PTR:回滚指针,通过这个指针可以找到该数据的历史版本,也就是所说的版本链。

        版本链就是用一个单链表的结构存放每个事务版本对应的行的数据,通过我当前的事务id可以获取对应的数据。

        Read View就是事务进行快照读操作的时候生产的可读视图(Read View),用来判断该数据版本是否可被访问,可读视图可以简单的理解成有三个全局属性:

        trx_list:存放当前正活跃的事务ID;
        low_limit_id:记录trx_list中事务ID最小的ID;
        up_limit_id:可读视图生成时当前全局事务ID的最大值(也有一说是目前已出现过的事务ID的最大值+1)。

二、原理及实现流程

        明白概念之后,我们一起探究一下MVCC到底是怎样的实现的。

        这里呢,要说一下可读视图判断数据版本是否可被访问的方式是怎样的:

        首先比较数据版本的事务ID(DB_TRX_ID )是否小于 low_limit_id, 如果小于,则表示此版本数据可被当前事务访问,如果不小于,接着判断事务ID是否大于或者等于up_limit_id,若是,则表示该数据版本实在可读试图生成之后才出现的,不可被访问,如果事务ID介于up_limit_idlow_limit_id之间,则拿着这个事务ID去和可读试图中事务列表里的事务ID作比较,如果一致,说明该数据版本未被提交,不可访问,反之,则可访问。

        我们举两个例子来更好地理解MVCC实现原理: 

        在读已提交的的事务隔离级别(RC)之下,假设事务A的事务ID是2,当事务 A 未提交时,事务 B 进行查询事务A操作的数据时,假设事务 B 的事务 ID 为 3,此时事务B的可读试图的的事务列表中为 [2,3],而数据的最新版本的 trx_id 为 事务A的事务ID,也就是2,根据上述判断规则,此时该版本的事务ID处于 事务列表中,则该版本数据不可被访问,接着继续查询版本链得到该记录的上一个事务ID为1的版本,显然是小于事务列表中的最小值也就是low_limit_id,因此可以被访问;当事务A提交之后,事务B再查询,此时事务列表里是3,拿到最新版本数据的事务ID还是2,小于3,此时可被访问。

        在重复读的事务隔离级别(RR)下,在事务A提交前后,事务B的可读视图始终为第一次查询时生成的,也就是事务列表仍然为[2,3],当事务A提交之后,数据版本的事务ID 也就是2,仍处于事务列表中,因此,数据版本不可访问,最后访问的还是事务ID为1的版本。这也就是可重复读前后查询保持数据一直的原因了。

    
 

        

Top