什么是 MVCC

来源:Python 技术「ID: pythonall」

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

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

假设数据库有如下记录。

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

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

一致性视图

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

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

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

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

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

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

实战分析

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

假设(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。

你要知道,读取数据是从当前版本往前读的,对于事务 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(多版本并发控制)的底层实现方式,虽然过程略显复杂,但这保证了在不加锁的情况下,保证了可重复读,和读提交。读写不互相干扰,能极大的提高并发能力。

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

参考

极客时间 「MySQL实战45讲 08节」。

(0)

相关推荐

  • 万字总结 MySQL核心知识,赠送25连环炮

    回复"000"获取大量电子书 前言 大家好,我是老田,之前写过 JVM.并发编程连环炮.然后有很多小伙伴私下找我就我继续把MySQL的连环炮整理出来,但是由于本人比较懒,又加上最近 ...

  • 跟面试官侃半小时MySQL事务隔离性,从基本概念深入到实现

    来源 | 阿丸笔记 提到MySQL的事务,我相信对MySQL有了解的同学都能聊上几句,无论是面试求职,还是日常开发,MySQL的事务都跟我们息息相关. 而事务的ACID(即原子性Atomicity.一 ...

  • 数据库中事务的几种隔离级别分别解决了哪些问题

    前面一直在写 JVM 系列的文章,直到有一天,卡壳了,后面不知道写啥了,原因就是笔者是一个菜鸟(公众号名称就能看出),懂得少,理解也不够透彻,导致差不多快两个月没更了(主要还是因为懒). 最近打开微信 ...

  • 在 MySQL 中是如何通过 MVCC 机制来解决不可重复读和幻读问题的?

    「不可重复读现象指的是,在一个事务内,连续两次查询同一条数据,查到的结果前后不一样」. 在 MySQL 的可重复读隔离级别下,不存在不可重复读的问题,那么 MySQL 是如何解决的呢? 答案就是 MV ...

  • MySQL数据库的事务及存储引擎

    一.关系型数据库与非关系型数据库 1.关系型数据库的特点: 1)数据以表格的形式出现 2)每行为各种记录名称 3)每列为记录名称所对应的数据域 4)许多的行和列组成一张表单 5)若干的表单组成数据库 ...

  • 还原面试现场-ACID与隔离级别

    前言 现如今JAVA开发工程师的数量越来越多,但大多数工程师平时做的工作都是简单的CRUD,当你一直处于这种舒适的环境中不追求进步的时候,如果哪一天你突然想要改变环境,换个工作,去与面试官当面聊技术的 ...

  • MySQL系列一:掌握MySQL底层原理从学习事务开始

    前言 面试时候,经常会被问到什么是事务.事务的特征.事务的隔离级别这些八股文问题,凭死记硬背通常也可回答的七七八八.但是面试官一旦换个角度问这些问题,有时候可能就语塞了. 所以学一个知识,我总在想有没 ...

  • MySQL(一):MySQL数据库事务与锁

    基本概念 事务是指满足ACID特性的的一组操作,可以通过Commit提交事务,也可以也可以通过Rollback进行回滚.会存在中间态和一致性状态(也是真正在数据库表中存在的状态) ACID Atomi ...

  • mysql中的事务隔离级别及可重复读读提交详细分析(mvcc多版本控制/undo log)

    一.事物隔离级别 读未提交(read uncommitted)是指,一个事务还没提交时,它做的变更就能被别的事务看到.通俗理解,别人改数据的事务尚未提交,我在我的事务中也能读到. 读提交(read c ...

  • 【MySQL笔记】正确的理解MySQL的乐观锁,悲观锁与MVCC

    正确的理解MySQL的乐观锁,悲观锁与MVCC 如果觉得对你有帮助,能否点个赞或关个注,以示鼓励笔者呢?!博客目录 | 先点这里 !首先声明,MySQL的测试环境是5.7 前提概念 数据库并发的三种场 ...

  • MySQL中的乐观锁,悲观锁和MVCC全面解析

    这篇文章主要介绍了MySQL中的乐观锁和悲观锁和MVCC全面解析的相关资料,帮助大家更好的理解和学习MySQL数据库,感兴趣的朋友可以了解下前言在数据库的实际使用过程中,我们常常会遇到不希望数据被同时 ...

  • Mysql多版本并发控制(MVCC)

    Mysql多版本并发控制(MVCC)Mysql和其他大多数数据库中的事务型存储引擎的实现一般都不是简单的行锁.一般基于提升并发性能考虑,他们一般都会实现多版本并发控制(MVCC),他们实现的机制都不太 ...

  • Mysql中的MVCC

    redo log redo log就是保存执行的SQL语句到一个指定的Log文件,当Mysql执行recovery时重新执行redo log记录的SQL操作即可.当客户端执行每条SQL(更新语句)时, ...

  • 看一遍就理解:MVCC原理详解

    前言 MVCC实现原理是一道非常高频的面试题,技术讨论群的小伙伴一直在讨论,趁着之前的国庆节长假,好好总结了一番,希望对你有所帮助. 1. 相关数据库知识点回顾 1.1 什么是数据库事务,为什么要有事 ...