<返回更多

全网最全一篇数据库MVCC详解,不全你打我

2020-09-15    
加入收藏

什么是MVCC

全称Multi-Version Concurrency Control,即多版本并发控制,主要是为了提高数据库的并发性能。以下文章都是围绕InnoDB引擎来讲,因为myIsam不支持事务。

同一行数据平时发生读写请求时,会上锁阻塞住。但mvcc用更好的方式去处理读—写请求,做到在发生读—写请求冲突时不用加锁。

这个读是指的快照读,而不是当前读,当前读是一种加锁操作,是悲观锁。

那它到底是怎么做到读—写不用加锁的,快照读和当前读又是什么鬼,跟着你们的贴心老哥,继续往下看。

当前读、快照读都是什么鬼

什么是MySQL InnoDB下的当前读和快照读?

当前读

它读取的数据库记录,都是当前最新的版本,会对当前读取的数据进行加锁,防止其他事务修改数据。是悲观锁的一种操作。

如下操作都是当前读:

快照读

快照读的实现是基于多版本并发控制,即MVCC,既然是多版本,那么快照读读到的数据不一定是当前最新的数据,有可能是之前历史版本的数据。

如下操作是快照读:

快照读与mvcc的关系

MVCCC是“维持一个数据的多个版本,使读写操作没有冲突”的一个抽象概念。

这个概念需要具体功能去实现,这个具体实现就是快照读。(具体实现下面讲)

听完贴心老哥的讲解,是不是瞬间茅塞顿开。

数据库并发场景

MVCC解决并发哪些问题?

mvcc用来解决读—写冲突的无锁并发控制,就是为事务分配单向增长的时间戳。为每个数据修改保存一个版本,版本与事务时间戳相关联。

读操作只读取该事务开始前的数据库快照。

解决问题如下:

因此有了下面提高并发性能的组合拳:

MVCC的实现原理

它的实现原理主要是版本链,undo日志 ,Read View 来实现的

版本链

我们数据库中的每行数据,除了我们肉眼看见的数据,还有几个隐藏字段,得开天眼才能看到。分别是db_trx_id、db_roll_pointer、db_row_id。

 

全网最全一篇数据库MVCC详解,不全你打我

 

如上图,db_row_id是数据库默认为该行记录生成的唯一隐式主键,db_trx_id是当前操作该记录的事务ID,而db_roll_pointer是一个回滚指针,用于配合undo日志,指向上一个旧版本。

每次对数据库记录进行改动,都会记录一条undo日志,每条undo日志也都有一个roll_pointer属性(INSERT操作对应的undo日志没有该属性,因为该记录并没有更早的版本),可以将这些undo日志都连起来,串成一个链表,所以现在的情况就像下图一样:

全网最全一篇数据库MVCC详解,不全你打我

 

对该记录每次更新后,都会将旧值放到一条undo日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被roll_pointer属性连接成一个链表,我们把这个链表称之为版本链,版本链的头节点就是当前记录最新的值。另外,每个版本中还包含生成该版本时对应的事务id,这个信息很重要,在根据ReadView判断版本可见性的时候会用到。

undo日志

Undo log 主要用于记录数据被修改之前的日志,在表信息修改之前先会把数据拷贝到undo log里。

当事务进行回滚时可以通过undo log 里的日志进行数据还原。

Undo log 的用途

undo log主要分为两种:

Read View(读视图)

事务进行快照读操作的时候生产的读视图(Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照。

记录并维护系统当前活跃事务的ID(没有commit,当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以越新的事务,ID值越大),是系统中当前不应该被本事务看到的其他事务id列表。

Read View主要是用来做可见性判断的, 即当我们某个事务执行快照读的时候,对该记录创建一个Read View读视图,把它比作条件用来判断当前事务能够看到哪个版本的数据,既可能是当前最新的数据,也有可能是该行记录的undo log里面的某个版本的数据。

Read View几个属性

Read View可见性判断条件

全网最全一篇数据库MVCC详解,不全你打我

 

全网最全一篇数据库MVCC详解,不全你打我

 

MVCC和事务隔离级别

上面所讲的Read View用于支持RC(Read Committed,读提交)和RR(Repeatable Read,可重复读)隔离级别的实现。

RR、RC生成时机

解决幻读问题

RC、RR级别下的InnoDB快照读区别

总结

从以上的描述中我们可以看出来,所谓的MVCC指的就是在使用READ COMMITTD、REPEATABLE READ这两种隔离级别的事务在执行普通的SEELCT操作时访问记录的版本链的过程,这样子可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能。

 


链接:https://juejin.im/post/6871046354018238472
来源:掘金

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>