Mysql高级之MVCC版本控制

什么是MVCC?

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

使用MVCC有什么好处(解决的问题)

SQL共有4中隔离级别分别为:读未提交,读已提交,可重复读,串行化。他们分别对3种读如下图:

脏读 不可重复读 幻读
读未提交 ×   × ×
读已提交 × ×
可重复读 ×
串行化

上述表格可以看到,从上至下,隔离级别越往下,性能越低,但是数据并发出现的问题就越小,而到串行化的时候,已经是最慢的性能了。然而MVCC版本并发控制,可以让可重复读也解决幻读问题,大大加强了sql的性能。如下图:

                

脏读 不可重复读 幻读
读未提交 × × ×
读已提交 × ×
可重复读/串行化

        可重复读/串行化,采用的是MVCC+Next-key lock 机制。

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

MVCC的实现原理

MVCC的实现原理就是:隐藏字段UNDO LOG字段链READ VIEW 视图

什么是Read View

在MVCC机制中,多个事务对同一个行记录进行多版本的更新时,会产生多个历史快照,而这些历史快照都保存在UNDO LOG中,如果一个事务想要查询这个行记录,需要读取那个版本的行记录呢?这时候就需要READ View视图,帮我们解决可见性问题。

ReadView就是事务在使用MVCC机制的时候进行快照读的操作,产生读视图。当事务启动时,会产生数据库系统当前的一个快照,InnDB为每个事务构造了一组数组,用来记录并维护系统当前活跃事务的ID。

而在ReadView视图中主要包含了4个重要内容:

        1、creator_trx_id:创建这个ReadView的事务Id

        2、trx_ids:表示在生成ReadView时,当前事务活跃的ID列表

        3、up_limit_id:活跃的事务最小的事务ID

        4、low_limit_id:表示系统最大事务ID+1

MVCC操作流程

当我们查询一条记录时,首先会获取事务自己的版本号,也就是自己的事务ID,然后会生成

undo log(历史快照)+ReadView 在ReadView中会通过最小事务的ID和当前的trx_ids进行比对,如果在当前活跃列表中,就继续向下寻找,直到找到小于自己的一条数据。

大白话将太难以理解,我们直接上图

注意:

       MVCC对应的3中级别

        读已提交:每次查询都会出现一个新的视图

        可重复读:在不提交事务的时候,每次查询都是第一次查询的视图

        串行化:和可重复读一样

MVCC读已提交的流程

我在网上找的一段截图,可以看一下

        使用读已提交的隔离级别:  每查询一次都会生成一个新的视图

              现在有两个事务 事务10 和事务20 

 可以看到事务10更新了一些数据,事务20没有更新数据,此时会生成一个undo log快照保存起来,当我们使用事务读取当前正在被操作的事务时,就会触发ReadView,在ReadView中会有4个关键性数据 creator_trx_id、 trx_ids、 up_limit_id、 low_limit_id 这几个数据在上述已经讲过,所以trx_ids为[10,20] ; up_limit_id为10;  low_limit_id为21 。

        在undo log的版本链中挑选数据,第一个是王五trx_id为10,发现已经在ReadView中的trx_ids的范围中,表示还未提交的事务,所以不能查询,接着就依次往下推,李四,也在活跃链中,推到张三trx_id为8时,发现不在活跃的版本链中,表示已经提交过了,可以查询该数据,所以就返回张三这条数据!

 再来看可重复读的级别:MVCC解决了幻读不可重复读问题

MVCC可重复读流程

还是看直接看图片,便于理解

 我们可以发现,这个得到的值为张三,和上述读已提交的操作一样

这一次查询生成的ReadView为 :trx_ids为[10,20] ; up_limit_id为10;  low_limit_id为21

因为当前的隔离级别为可重复读,所以,接下来的事务都会使用这个ReadView视图

 我们发现它的undoLog版本链发生了变化,但是他的视图ReadView还是第一次查询的视图,第一次查询的视图中的trx_ids[10,20]

所以,在undolog通过trx_id和ReadView进行对比时,最后还是查询到的张三这条数据!

MVCC幻读的流程

如果上述两个隔离级别理解了,幻读的时候就很好理解了,因为幻读也是在第一次查询的时候生成ReadView视图,所以接下来,不管查询几次,都只会有这一个视图,因此当我们进行插入数据完成后,在进行undolog链和ReadView进行对比时,发现,插入的新数据在活跃id中,所以查询不到当前数据,接下来也是依次往下查找,直到找到不在版本链中的数据!

猜你喜欢

转载自blog.csdn.net/wang20000102/article/details/132294018
今日推荐