美文网首页
MySQL-MVCC

MySQL-MVCC

作者: 小马蛋 | 来源:发表于2019-11-18 11:58 被阅读0次

    一、阐述

    mvcc(multi version concurrency control)多版本并发控制,其作用就是在让特定隔离级别的事务在并发时,保证在事务中能实现一致性读(无法保证写一致性),虽然锁可以控制并发操作,但是锁的系统开销比较大,而mvcc可以在大多数情况下替代行级锁,同时可以降低系统开销。

    二、原理

    对于Innodb存储引擎来说,每个聚簇索引记录中都包含两个隐藏列:

    1)trx_id:每当一个事务对记录进行修改时,都会将该事务的id记录在这个列里。

    2)roll_pointer:每当一个事务对记录进行修改时,都会把旧版本写入undo日志中,这个隐藏列的作用就是指向此记录修改前的信息。

    示例1.jpg

    每次修改记录,都会向undo日志增加一条记录,每条undo记录都都有一个roll_pointer属性(insert操作对应的undo日志没有该属性),用以将这些undo日志串成一个链表。如下:

    两个事务都对id=1的记录进行修改。

    示例2.jpg

    这些undo日志将会串成一个链表,如下:

    示例3.png

    对此记录每次修改后,都会将旧值作为一条记录放入undo日志中,随着操作的累加,通过roll_pointer就会形成一个链表,即版本链,这个版本链的头结点就是此记录的最新值。

    insert undo 在事务提交后就会删除,因为它初始化后本身就在版本链头结点,所以继续存储在undo日志中没有必要,但是update undo为了继续支持mvcc,所以继续存在于undo日志中。

    为了支持MVCC,对于delete mark操作来说,仅仅是在记录上打一个删除标记,并没有真正将它删除掉。

    在接下来的时间,MySQL系统会判断哪些undo日志不会再被访问了,后台运行的purge线程会把它们删除。

    三、ReadView

    作用:通过ReadView可以找到当前事务能访问的记录。

    两种隔离级别不需要ReadView:

    1)READ UNCOMMITTED读未提交,每次都获取最新的值就行了,不需要在版本链里查询符合自己条件的旧数据。

    2)SERIALIZABLE 串行化,InnoDB存储引擎,为SERIALIZABLE隔离级别提供加锁的访问方式(读写锁),只有一个事务结束,另外一个事务才可以进行操作。

    两种隔离级别需要ReadView:

    READ COMMITTEDREPEATABLE READ,都必须保证读到已提交的事务修改的记录。

    ReadView有四个属性:

    1)m_ids

    表示生成ReadView时,当前数据库系统中活跃的读写事务id列表。

    2)min_trx_id

    表示在生成ReadView时,当前数据库系统中活跃的读写事务中事务id最小的事务,对应m_ids中的最小值。

    3)max_trx_id

    表示生成ReadView时,数据库系统准备给下一个事务分配的id

    4)creator_trx_id

    表示生成ReadView的事务id

    通过ReadView判断某个版本记录是否对当前事务可见

    在讲如何判断之前,我们一定要知道事务id是什么时候分配的。

    在《MySQL事务隔离级别》这篇文章里有提到过。不熟悉的请去翻一翻,否则,在下面讲解过程中容易翻车。

    判断:

    1)如果被访问记录的事务id(trx_id)与ReadView中的creator_trx_id相同,意味着当前的事务正在访问被它修改过的记录,所以该版本的记录可以被当前事务访问。

    2)如果被访问记录的事务id(trx_id)小于ReadView中的min_trx_id,表明生成该记录的事务在生成ReadView时已经提交,所以该版本的记录可以被当前事务访问。

    3)如果被访问记录的事务id(trx_id)大于或等于ReadView中的max_trx_id,表明生成该记录的事务在生成ReadView的事务之后,才开启(创建)的,所以该版本的记录不能被当前事务访问。

    4)如果被访问记录的事务id(trx_id)在min_trx_id 和 max_trx_id之间,需要判断trx_id是否在m_ids列表中,如果在,说明生成ReadView时,trx_id对应的事务是活跃的,该版本的记录不可被当前事务访问,如果不存在,说明创建ReadView时,trx_id对应的事务已经提交,该版本的记录可以被当前事务访问。

    如果某个版本的记录不可以被当前事务访问,MySQL会沿着undo版本链一直向下查找,直到最后一条数据,如果最后一条记录也不可以被当前事务访问,那就说明此记录对该事务完全不可见,查询结果就不会包含这条记录。

    ReadView的生成时机

    上面介绍了MySQL只有在READ COMMITTEDREPEATABLE READ两种隔离级别下,才会生成,但是这两种隔离级别生成ReadView的时机是不同的:

    1)READ COMMITTED在每次查询时都会生成ReadView。

    2)REPEATABLE READ在第一次查询时生成ReadView,之后在这个事务内的所有查询操作,不再生成ReadView。

    四、讲解

    1)READ COMMITTED 隔离级别

    示例4.png

    2)REPEATABLE READ 隔离级别

    示例5.png

    相关文章

      网友评论

          本文标题:MySQL-MVCC

          本文链接:https://www.haomeiwen.com/subject/hxlpictx.html