什么是 MVCC

简介: 上一篇文章我们说到数据库的四种事务隔离级别,可以通过加锁的方式来实现,只是效率太低,事实上,MySQL 是通过 MVCC(多版本并发控制)来实现的。具体原理有一点点复杂,需要你用点心才能看懂,今天我们就以「可重复读隔离级别」为例来详细说明其具体原理。

上一篇文章我们说到数据库的四种事务隔离级别,可以通过加锁的方式来实现,只是效率太低,事实上,MySQL 是通过 MVCC(多版本并发控制)来实现的。

具体原理有一点点复杂,需要你用点心才能看懂,今天我们就以「可重复读隔离级别」为例来详细说明其具体原理。

假设数据库有如下记录。

54.jpg

我们都知道 InnoDB 引擎下,每一个事务都有一个事务 ID,叫做 transaction id,是在事务开始时系统自动分配的,且该 id 是递增的。同时这个 id 也会记录在数据行上面。言外之意就是数据库表的每行记录是有多个版本的,用事务 ID 来标示这行记录是属于哪个事务操作的。既然是有多个版本,那怎么拿到旧版本的数据记录呢,答案就是在添加一个指针,指向前一个事务 ID 标识的记录。

55.jpg

而这个指针就是我们通常诉所说的 undo log,事实上,旧版本的行记录都不是物理存在的,而是通过 undo log 实时计算出来的。

一致性视图

好了,了解了行记录事务 ID 和回滚指针的概念之后,我们来看看一致性视图。

当在一个事务 A 中查询数据时,只需要确定行记录的数据版本是否在事务 A 启动之前生成的即可,如若是,则可见;否则不可见,则需通过回滚指针找到上一个版本来继续判断属否可见,

因此,就需要在事务启动时,为该事务构造一个事务数组,用来保存该事务启动瞬间,系统中正在活跃的所有事务 ID,也就是启动了但还未提交的事务 ID。

数组中的最小值我们简记为低位,系统中的最大事务 ID 记录为高位,正是这个高位和视图数组组成了我们说的「一致性视图」。

因此,对于任何一个事务 A 来说,任何数据版本的可见行都可以通过一致性视图来得到。

  1. 如果数据版本小于低位,说明是已经提交的记录,则可见。
  2. 如果大于高位,说明是由未来的事务生成的,则不可见。
  3. 如果在高位和低位之间:
  1. 若在数组中,说民该事务还未提交,则不可见,
  2. 如果不在数组中,说明该事务是已经提交了的,则可见。

实战分析

我们针对上图的数据记录,假设有以下三个事务,我们来具体分析下,其一致性视图是怎么样的。

55.jpg

假设(1,1)这行记录的事务 ID 是 90;事务 A 开启前,系统里面只有一个活跃的事务,ID = 99;事务 A、B、C 的版本号分别是 100、101、102。

现在,事务 A、B、C 的视图数组和高位分别是[99,100]/101,[99,100,101]/102,[99,100,101,102]/103。

56.jpg

你要知道,读取数据是从当前版本往前读的,对于事务 A 来说:

  1. 当读取到 (1,3) 的时候,事务 ID = 101,高于高位,不可见。
  2. 往前读取历史版本(1,2),事务 ID = 102,高于高位,不可见。
  3. 继续往前读取历史版本(1,1),事务 ID = 90,低于低位,可见。

这样,我们就通过一致性视图和事务 ID 找到了可见的数据版本,不论事务 A 是什么时候查询的,看到的记录都是一致的。

读提交

上面我们分析了可重复读隔离级别下的一致性视图,那么在读取提交的隔离级别下,又是怎么样的呢?

事实上,他们最主要的区别就是一致性视图的创建时间不一样,对于可重复读隔离级别,一致性视图是在事务开启时刻生成的,之后在该事务中的查询都共用这个一个视图。而对于读提交隔离级别,每一个语句执行前都会生成一个新的视图。

因此,事务 A、B、C 的视图数组和高位分别是[99,100,101]/103,[99,101]/103,[99,102]/103。

对于事务 A 来说:

  1. 当读取到 (1,3) 的时候,事务 ID = 101,在数组中,不可见。
  2. 往前读取历史版本(1,2),事务 ID = 102,不在数组中,可见。

总结

今天我们学习了 MVCC(多版本并发控制)的底层实现方式,虽然过程略显复杂,但这保证了在不加锁的情况下,保证了可重复读,和读提交。读写不互相干扰,能极大的提高并发能力。

别看上面的分析步骤较复杂,事实上我们只需要记住以下两条规则即可。在可重复读隔离级别下,查询只能看到在事务启动前已经提交的数据。在读提交隔离级别下,查询只能看到在语句启动前已经提交的数据。

目录
相关文章
|
24天前
MVCC是什么
MVCC是多版本并发控制,为每次事务生成一个新版本数据,每个事务都有自己的版本,从而不加锁就拒绝读写冲突,这种读叫做快照读。只在读已提交和可重复读中生效。 实现原理由四个东西保证,他们是: undolog日志:记录了数据历史版本 readView:事务进行快照读时产生的视图,记录了当前系统中活跃的事务id,控制哪个历史版本对当前事务可见 隐藏字段DB_TRC_ID: 最近修改记录的事务ID 隐藏字段DB_Roll_PTR: 回滚指针,配合undolog指向数据的上一个版本
|
2月前
MVCC 与其他并发控制机制的区别
【10月更文挑战第15天】总之,MVCC 与其他并发控制机制各有特点和适用场景。在实际应用中,需要根据具体的业务需求和系统特点选择合适的并发控制机制,以实现最佳的性能和数据一致性。
|
2月前
|
存储 数据库 数据安全/隐私保护
MVCC实现原理
【10月更文挑战第15天】MVCC 通过维护版本链和相关信息,实现了在多事务并发环境下的数据隔离和并发控制,提高了数据库的性能和可用性。
|
4月前
|
存储 Java 数据库
|
3月前
|
关系型数据库 MySQL 数据库
InnoDB 的 MVCC 实现原理
InnoDB 的 MVCC 实现原理
49 0
|
4月前
|
关系型数据库 MySQL 数据库
为什么需要MVCC 隔离级别
【8月更文挑战第5天】
55 7
|
6月前
|
关系型数据库 MySQL 数据库
InnoDB-MVCC多版本控制详解
InnoDB-MVCC多版本控制详解
|
7月前
|
存储 关系型数据库 MySQL
什么是MVCC?看看它的实现原理
之前在讲 MySQL 事务隔离性提到过,对于写操作给读操作的影响这种情形下发生的脏读、不可重复读、虚读问题,是通过MVCC 机制来进行解决的,那么MVCC到底是如何实现的,其内部原理是怎样的呢?我们要抓住三个方面:记录中的4个隐藏字段、undo log 和 read view。
477 0
什么是MVCC?看看它的实现原理
|
7月前
|
存储 缓存 关系型数据库
RR有幻读问题吗?MVCC能否解决幻读?
RR有幻读问题吗?MVCC能否解决幻读?
65 0
RR有幻读问题吗?MVCC能否解决幻读?
|
存储 算法 Oracle
PostgreSQL的MVCC vs InnoDB的MVCC
PostgreSQL的MVCC vs InnoDB的MVCC
99 0
PostgreSQL的MVCC vs InnoDB的MVCC