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

「不可重复读现象指的是,在一个事务内,连续两次查询同一条数据,查到的结果前后不一样」。

在 MySQL 的可重复读隔离级别下,不存在不可重复读的问题,那么 MySQL 是如何解决的呢?

答案就是 MVCC 机制。MVCC 是 Mutil-Version Concurrent Control(多版本并发控制)的缩写,它指的是数据库中的每一条数据,会存在多个版本。对同一条数据而言,MySQL 会通过一定的手段(ReadView 机制)控制每一个事务看到不同版本的数据,这样也就解决了不可重复读的问题。

假设现有一条数据,它的 row_trx_id=10,数据的值为 data0,它的 roll_pointer 指针为 null。

假设现在有事务 A 和事务 B 并发执行,事务 A 的事务 id 为 20,事务 B 的事务 id 为 30。

现在事务 A 开始第一次查询数据,那么此时 MySQL 会为事务 A 产生一个 ReadView,此时 ReadView 的内容如下:m_ids=[20,30],min_trx_id=20,max_trx_id=31,creator_trx_id=20。

此时由于数据的最新版本的 row_trx_id=10,「小于事务 A 的 ReadView 中的 min_trx_id,这表明这个版本的数据是在事务 A 开启之友链交易前就提交的」,因此事务 A 可以读取到数据,读取到的值为 data0。

「结论:事务 A 第一次查询到的数据为 data0」

接着事务 B(trx_id=30)去修改数据,将数据修改为 data_B,并提交事务,此时 MySQL 会写一条对应的 undo log,数据就会新增一个版本,undo log 版本就变成了如下图所示的结构,数据的最新版本的 row_trx_id 就是事务 B 的事务 id,即:30。此时,事务 B 已经提交了,因此系统中活跃事务的数组里就没有 30 这个 id 了。

「重点来了,事务 A 的 ReadView 是在发起第一次查询的时候创建的,当时系统中的活跃事务有 20 和 30 这两个 id,那么此时当事务 B 提交以后,事务 A 的 ReadView 的 m_ids 会变化吗?不会。因为是可重复读隔离级别下,对于读事务,只会在事务查询的第一次创建 ReadView,后面的查询不会再重新创建」

接着事务 A(trx_id=20)开始第二次查询数据,前面事务 A 已经创建了 ReadView,所以在第二次查询时,不会再重复创建 ReadView 了。

此时在 undo log 版本链中,数据最新版本的事务 id 为 30,根据 ReadView 机制(什么是 ReadView 机制,可以去阅读上一篇文章),发现 30 处于事务 A 的 ReadView 中 min_trx_id 和 max_trx_id 之间,因此还需要判断 30 是否处于 m_ids 数组内,结果发现 30 确实在 m_ids 数组中,「这就表示这个版本的数据是和自己在同一时刻开启事务所提交的,因此不能让自己读取。」

所以此时事务 A 需要沿着 undo log 版本链继续向前找,最终发现 row_id=10 的版本数据自己可以读取到,因此事务 A 查询到的值是 data0。

「结论:事务 A 第二次查询到的数据为 data0。这与事务 A 第一次查询的数据结果相同,没有出现不可重复读的现象。」

那假设后来又创建了一个事务 C,id 为 40,并且事务 C 将数据修改为了 data_C。然后数据的 undo log 版本链变

然后事务 A 发起第三次查询,此时事务 A 仍然不会再重新创建 ReadView,所以此时它的 ReadView 依旧是:m_ids=[20,30],min_trx_id=20,max_trx_id=31,creator_trx_id=20。

由于数据最新的版本的为 trx_id=40,依照 ReadView 机制,40 大于事务 A 中的 max_trx_id,「这表示这是在事务 A 开启之后的事务提交的数据,因此事务 A 不能读取到」,所以需要沿着 undo log 版本链往前找,然而 trx_id=30 的版本事务 A 也不能读到,继续向前找,最终读取到 trx_id=10 的版本数据,即 data0。

(0)

相关推荐

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

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

  • 什么是 MVCC

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

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

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

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

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

  • 顺丰快递:请签收MySQL灵魂十连问

    顺丰快递:请签收MySQL灵魂十连问

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

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

  • 记一次MySQL中Waiting for table metadata lock的解决方法

    最近项目中的数据库查询经常挂起,应用程序启动后也报操作超时.测试人员就说数据库又挂了(貌似他们眼中的连接失败,查询无果都是挂了),通过 show processlist 一看,满屏都是 Waiting ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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