MySQL高级:详解MVCC多版本控制(对锁的替代)

MVCC是一种用于提高数据库并发性能的技术,主要用于解决读已提交和可重复读的隔离级别。通过数据行的多个版本管理,每个事务根据ReadView判断可见性。ReadView在读已提交隔离级别下每次SELECT都会更新,而在可重复读隔离级别下只在首次SELECT时生成。MVCC通过undo日志和隐藏字段如trx_id、roll_pointer实现并发控制。
摘要由CSDN通过智能技术生成

0、前言

        本节要求的基础是,学习了数据库的几大读写问题和隔离级别后(如脏读、不可重复读、幻读;读未提交、读已提交、可重复读和串行序列化)、数据库的锁(读锁、写锁等)、并且在学习了UNDO日志的基本知识后,本文将介绍一项技术用于替代锁的控制。

1、总体概括:什么是MVCC多版本控制        

        加锁,是一种悲观锁、非阻塞并发读,为了提高数据库的并发性能,更好地处理读写重读,需要引入MVCC多版本控制技术来替代锁。

        而MVCC技术主要解决的问题就是:读已提交、可重复读,这两种隔离级别的底层是如何实现的呢——通过MVCC实现!

        其次,“多版本控制”,是通过数据行的多个版本管理,来实现并发控制。
        例如,你想进行可重复读,那要读的就不该是另外一个已提交事务修改后的数据,而是最初版本的数据。我们可以通过多版本控制实现这类的操作,从而完成读已提交、可重复读。

2、基础知识

2.1 数据的隐藏字段

        undo日志的版本链:对于使用 InnoDB 存储引擎的表来说,它的聚簇索引记录中都包含两个必要的隐藏列

  1. trx_id:系统在每次一个事务对某条聚簇索引记录进行改动update时,都会把该事务的 事务id 赋值给 trx_id 隐藏列(这个id是递增的),如果为查询操作,id默认为0。
  2. roll_pointer:每次对某条聚簇索引记录进行改动update时,都会把旧的版本写入到 undo日志中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。

        例如图下所示,对记录进行反复的改动,就会形成链表,我们把这个链表称之为 版本链

 2.2  ReadView(每个事务开始时都会构建一个它)

        ReadView是实现MVCC(多版本并发控制)机制的核心组件。

         ReadView是在执行可重复读和读已提交隔离级别事务时创建的一个数据结构,用于识别出所读取行的可见性。在每个事务开始时,MySQL会将当前系统中所有活跃事务的ID号和其启动时创建的快照信息构建成一个ReadView。这个ReadView中包含了以下几个主要的元素

 3、ReadView规则       

        在隔离级别为读已提交(Read Committed)时,一个事务中的每一次 SELECT 查询都会重新获取一次 Read View。
        当隔离级别为可重复读的时候,就避免了不可重复读,这是因为一个事务只在第一次 SELECT 的时候会 获取一次 Read View,而后面所有的 SELECT 都会复用这个 Read View下。

        有些晦涩,直接通过例子进行讲述:

4、MVCC流程示例

 4.1 例1:读已提交

(1)构建两个事务10、20(系统自动分配事务id),都没提交:

(2)用可重复读,去查询,理论上应该查出张三:后面要通过MVCC解释为什么是张三:

分析:

        当前是读的操作,因此生成ReadView的creator_trx_id为0,活跃事务列表trx_id为[10,20],up为10,low为21.
        然后去依次查版本链表,王五的trx_id是10,在[10,20]里,因此还是活跃的,不能读。李四同理,等到张三trx_id是8 < up,因此把张三读出来。

(3)提交事务id为10的事务再更新事务20,链表变为如下:

 此时再查一遍:

分析:

        每个事务中每次select都要生成ReadView(Read committed情况下),此时ReadView里的trx_id为[20],依次读undo日志,直到王五的trx_id为10<20,则查到王五。

 4.2 例2:可重复读

        使用 REPEATABLE READ 隔离级别的事务来说,只会在第一次执行查询语句时生成一个 ReadView ,之后的查询就不会重复生成了。       

        

 分析:

        前面步骤与可重复读一样,区别在于,提交以后,现在要可重复而不是读提交的:因为ReadView一直是最初的样子,即
        ReadView的creator_trx_id为0,活跃事务列表trx_id为[10,20],up为10,low为21.
        因此,一直找到trx_id==8 < 10的张三,才查找出来结果。

 5、总结

        无论事务是否提交,都会在undo日志中留下链表记录。区别在于,提交与否会改变ReadView里的活跃事务列表trx_id,这是判断版本号是否合规的关键。

        但是由于,不同的事务隔离级别而言,读已提交才对trx_id的变化敏感,而可重复读的情况下,只读一次ReadView,因此它怎么变化也就无所谓了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

好奇的7号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值