MySQL MVCC

目录

1.什么是多版本并发控制

2.快照读与当前读

2.1 快照读

2.2 当前读

3.复习

3.1 复习隔离级别

3.2 隐藏字段、undo log版本链

4.MVCC实现原理之ReadView

4.1 什么是ReadView

4.2 设计思路

4.3 ReadView规则

4.4 MVCC整体执行流程


1.什么是多版本并发控制

        MVCC(Multiversion Concurrency Control),多版本并发控制。顾名思义,MVCC是通过数据行的多个版本管理来实现数据库的并发控制。这项技术使得在InnoDB的事务隔离级别下执行一致性读操作有了保证。换言之,就是为了查询一些正在被另一个事务更新的行,并且可以看到他们被更新之前的值,这样在做查询的时候就不用等待另一个事务释放锁。

2.快照读与当前读

        MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁非阻塞并发读,而这个读指的就是快照读。当前读实际上是一种加锁的操作,属悲观锁的实现,而MVCC本质是采用乐观锁思想的一种方式。

2.1 快照读

        快照读又叫一致性读,读取的是快照数据。不加锁的简单select语句都属于快照读,即不加锁的非阻塞读。快照读的实现是基于MVCC,它在很多情况下避免了加锁操作,降低了开销。既然是基于多版本,那么快照读可能读到的并不是最新版的数据,而有可能是之前的历史数据。

        快照读的前提是隔离级别不能是串行化,串行化级别下快照读会退化为当前读。

2.2 当前读

        当前读读取的是记录行最新的版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。以下语句会造成当前读:

        select * for student for share

        select * for student for update

        insert into student values

        delete from student where

        update student set

3.复习

3.1 复习隔离级别

        我们知道事务有4个隔离级别,可能存在三种并发问题:

        在MySQL中,默认的隔离级别是可重复读,可以解决脏读和不可重复读,如果仅从定义的角度来看,它并不能解决幻读。如果我们想解决幻读,就必须采用串行化的方式,也就是将隔离级别提升到最高,但这样一来就会大幅降低数据库事务的并发能力。

        MVCC可以不采用锁机制,而是通过乐观锁的方式来解决不可重复读和幻读。它可以在大多数情况下替代行级锁,降低系统开销。

3.2 隐藏字段、undo log版本链

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

        trx_id:每次一个事务对某条聚簇索引记录进行更改时,都会把该事务的事务id赋值给trx_id隐藏列。

        roll_pointer:每次对某条聚簇索引记录进行更改时,都会把旧的版本写入到undo日志中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。

举例:student表结构如下

  

        假设插入该记录的事务id为8,那么此刻该条记录的示意图如下所示:

        insert undo只在事务回滚时起作用,当事务提交后,该类型的undo日志就没用了,它占用的undo log segment也会被系统回收(该undo log日志占用的undo页面链表要么被重用,要么被释放)

        假设之后两个事务id分别为10、20的事务对这条记录进行updat操作,操作流程如下:

        每次对记录进行改动,都会记录一条undo日志,每条undo日志也都有一个roll_pointer属性(insert操作对应的undo日志没有该属性,因为该记录并没有更早的版本),可以将这些undo日志都连起来,串成一个链表:

        对该记录每次更新后,都会将旧的值放到一条undo日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被roll_pointer属性连接成一个链表,我们把这个链表称之为版本链,版本链的头节点就是当前记录最新的值。

        每个版本中还包含生成对该版本时对应的事务id。

4.MVCC实现原理之ReadView

        MVCC的实现依赖于:隐藏字段、Undo Log、Read View

4.1 什么是ReadView

        在MVCC中,多个事务对同一个行记录进行更新会产生多个历史快照,这些历史快照保存在undo log中。问题:如果一个事务想要查询这个行记录,需要读取哪个版本的记录呢?答案:这时候就需要用到ReadView了,它解决了行可见性问题。

        ReadView就是事务在使用MVCC机制进行快照读操作时产生的读视图。当事务启动时,会生成数据库系统当前的一个快照,InnoBD为每个事务构造了一个数组,用来记录并维护系统当前活跃事务的id("活跃"指的是创建但还未提交的事务)

4.2 设计思路

        在使用读未提交隔离级别时,由于读未提交允许读取到未提交事务修改过的记录,所以直接读取记录行最新的版本就好了。

        在使用串行化隔离级别时,InnoDB规定使用加锁的方式来访问记录。

        使用读已提交可重复读时,InnoDB需保证读取到的必须是其他已提交事务修改过的记录。假如另一个事务已经修改了记录但尚未提交,是不能直接读取最新版本记录的。所以核心问题是需要判断一下记录版本链中哪个版本是当前事务可见的。ReadView就是用来解决这个问题。

ReadView中包含四部分内容,分别为:

        creator_trx_id:创建此ReadView的事务id

        trx_ids:表示在生成的ReadView时当前系统中活跃事务的事务id列表

        up_limit_id:活跃事务中最小的事务id

        low_limit_id:生成ReadView时系统应该分配给下一个事务的id值。

        注:low_limit_id并不是trx_ids中的最大值而是当前数据库已存最大活跃事务id + 1。比如,现有id为1、2、3的三个事务,后id为3的事务提交了。那么一个新的读事务在生成ReadView时,trx_ids就包括1和2,up_limit_id为1,low_limit_idi为4。

4.3 ReadView规则

        有了ReadView后,在访问某条记录时,只需要按照下面的步骤判断记录的某个版本是否可见。

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

        2.如果被访问记录的版本trx_id小于up_limit_id值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问。

        3.如果被访问记录的版本trx_id大于或等于ReadView中的low_limit_id,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。

        4.如果被访问记录的版本trx_id在ReadView中up_limit_id和low_limit_id之间,就需要判断一下trx_id是否在trx_ids列表中。

        如果在,说明创建ReadView时生成的该版本的事务还是活跃的,该版本不可以被访问。

        如果不在,说明创建ReadView时生成的该版本的事务已经被提交,该版本可以被访问。

4.4 MVCC整体执行流程

        了解这些概念之后,我们来看下当前查询一条记录的时候,系统如何通过MVCC找到它:

        1.获取事务自己的版本号,即事务id

        2.获取ReadView

        3.查询对应数据,然后与ReadView中的事务版本号进行比较

        4.如果不符合ReadView规则,就从undo log中获取历史记录快照,从版本链中找到下一版本的数据,再次与ReadView中的事务版本号进行比较。

        5.以此查找下去,最后返回符合规则的数据

        如果某个版本的数据对当前事务不可见,那么InnoDB会顺着版本链找到下一个版本的数据,继续按照上面的步骤判断可见性,以此类推,直到版本链中的最后一个版本。如果最后一个版本判断过后也不可见的话,那么就意味着记录对该事务完全不可见,查询结果就不包含该记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值