什么是MVCC

MVCC是通过数据行的多个版本管理来实现数据库的并发控制
就是为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值,这样在做查询的时候就不用等待另一个事务释放锁

快照读和当前读

MVCC做到的就是,即使存在读写冲突时,也能做到不加锁,非阻塞并发读,这个读指的就是快照读,而非当前读。当前读实际上是一种加锁的操作,是悲观锁的实现,而MVCC本质采用乐观锁思想的一种方式

快照读

快照读又叫做一致性读,读取的是快照数据,不加锁的简单的select都属于快照读,即不加锁的非阻塞读

快照读是基于MVCC,它在很多情况下避免了加锁操作,降低了开销。
由于是基于多版本,那么快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本
快照读的前提是隔离级别不是串行化,串行化下的快照读会退化成当前读

当前读

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

隔离级别

image.png

隐藏字段,Undo Log版本链

image.png
每次对记录进行改动时,都会记录一条undo日志,每条undo日志也都有一个roll_pointer属性(insert操作对应的undo日志没有该属性,因为该记录没有更早的版本),可以将这些undo日志都连接起来,串成一个链表
image.png
对该记录每次更新之后,都会将旧值放在一条undo日志当中,记录该旧版本,随着修改次数增多就会形成版本链
,每个版本中还包含了生成该版本时对应的事务id

MVCC实现原理之ReadView

MVCC的实现依赖于:隐藏资源,Undo Log,Read View

ReadView的概念

是事务开启时,当前所有活跃事务(还未提交的事务)的一个集合,ReadView数据结构决定了不同事务隔离级别下,数据的可见性

MySQL官方文档说明

Read view lists the trx ids of those transactions for which a consistent read should not see the modifications to the database.

ReadView的结构

1.creator_trx_id 创建这个Read View的事务ID(只有在对表中记录做出改动时才会有事务id,select记录为0)
2.trx_ids 表示在生成ReadView时当时系统中活跃的读写事务的 事务id列表
3.up_limit_id 活跃事务中最小的事务id
4.low_limit_id 表示生成ReadView时系统中应该分配给下一个事务的id值,low_limit_id是系统最大的事务id值,
image.png

ReadView的规则

有了ReadView,这样在访问某条记录时,只需要按照如下步骤判断记录的某个版本是否可见
1.如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同,意味着当前事务在访问他自己修改过的记录,所以该版本可以被当前事务访问
2.如果被访问版本的trx_id属性值小于ReadView中的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时生成该版本的事务已经被提交,该版本可以被访问

MVCC整体操作流程

当我们查询一条记录时,系统如何通过MVCC找到他
1.首先获取事务自身的版本号,也就是事务id
2.获取ReadView
3.查询得到的数据,然后与ReadView中的事务版本号进行比较
4.如果不符合ReadView规则,就需要从Undo Log中获取历史快照
5.最后返回符合规则的数据

在隔离级别为读已提交时,一个事务中的每一次select查询都会重新获取一个ReadView

注意,此时同样的查询语句都会重新获取一次 Read View,这时如果 Read View 不同,就可能产生 不可重复读或者幻读的情况。

当隔离级别为可重复读的时候,就避免的不可重复读,这是因为一个事务只在第一次select的时候会获取一次ReadView,后面所有的select都会重复使用这个readveiw

如何解决幻读

image.png
image.png
image.png

总结

在MVCC的读已提交和可重复读,这两种隔离级别的事务在执行快照读操作时访问记录的版本链的过程,这样使不同事务的读写,写读操作并发执行,从而提升系统性能

核心点在于ReadVeiw的原理,读已提交和可重复读这两个隔离级别的最大不同便是生成ReadView的时机不同