【MySQL】一文彻底吃透MVCC执行原理

news2024/9/25 23:25:48

1.MVCC是什么?

MVCC全称Multi-Version Concurrency Control,即多版本并发控制。它通过维护数据的多个版本来实现高效的并发控制,用于在多个并发事务同时读写数据库时保持数据的一致性隔离性

在搞清楚MVCC的实现原理之前,还需要了解快照读和当前读的概念。

一致性非锁定读(快照读)

简单的select语句(不加锁)就是快照读,读取的是记录数据的可见版本,不加锁,是非阻塞读。

  • select ...

一致性锁定读(当前读)

读取的是记录的最新版本,读取时需要保证其他并发事务不能修改当前记录,会对读取的记录加锁。如果执行的是下列语句,就是锁定读。

  • select ... lock in share mode
  • select ... for update
  • insertupdatedelete 操作

2.MVCC实现原理

MVCC 的实现依赖于:隐藏字段、Read View、undo log

隐藏字段

在内部,InnoDB 存储引擎为每行数据添加了三个隐藏字段

隐藏字段含义
DB_ROW_ID(6字节)隐藏主键,如果当前表不存在主键,则将该隐藏字段作为主键
DB_TRX_ID(6字节)最近修改事务ID,记录插入这条数据或最后一次修改该记录的事务ID
DB_ROLL_PTR(7字节)回滚指针,指向这条记录的上一个版本,用于配合undo log

假设有一个学生表,该表没有指定主键。

那么该表实际上的字段如下,如果存在主键则不存在DB_ROW_ID字段。

undo log

undo log 分为两种类型:insert undo logupdate undo log

  • Insert undo log 是在事务进行插入操作时生成的日志。其主要作用是用于事务回滚时撤销插入操作。该日志只在回滚时需要,在事务提交后,可被立即删除。
  • Update undo log 是在事务进行更新或删除操作时生成的日志。其主要作用是用于事务回滚时撤销更新和删除操作。该日志不仅在回滚时需要,在快照读时也需要,不会被立即删除。

一条记录的每一次更新操作产生的 undo log 格式都有一个一个 DB_TRX_ID事务id 和 DB_ROLL_PTR 指针:

  • 通过 DB_TRX_ID 可以知道该记录是被哪个事务修改的;
  • 通过 DB_ROLL_PTR 指针可以将这些 undo log 串成一个链表,这个链表就被称为版本链;

举例说明:

事务1已经提前执行了INSERT INTO user (id, age, name) VALUES (10, 10, 'Jack');语句插入了一条记录。则DB_TRX_ID(插入这条数据或最后一次修改该记录的事务ID)为1,由于insert undo log在事务提交后自动删除,所以不存在undo log日志,DB_ROLL_PTR为null。

该示例中有四个并发事务,其他事务在不同的时刻将执行update语句修改记录。

所有事务执行完毕后,当前记录的DB_TRX_ID为4,且形成了一条Update Undo Log版本链,后续MVCC可以利用这条版本链获取旧数据。

Read View

ReadView(读视图)是快照读执行时MVCC获取数据的依据,记录并维护系统尚未提交的事务(也称为活跃事务)id。

ReadView有以下四个重要字段:

字段含义
m_ids当前活跃事务的ID集合
min_trx_id最小活跃事务ID
max_trx_id预分配事务ID,当前最大事务ID+1(事务ID自增)
creator_trx_idReadView创建者的事务ID

Tips:m_ids的长度可不是max_trx_id - min_trx_id,因为m_ids是当前活跃事务的ID集合,在min_trx_idmax_trx_id即可能有活跃事务,也可能有非活跃事务

当一个事务需要读取一条记录时,需要遵循以下四条规则进行读取(非常重要):

  1. DB_TRX_ID == creator_trx_id时,说明该数据就是当前事务更改的,可以访问该版本

  2. DB_TRX_ID < min_trx_id 时,比最小活跃事务ID小,说明当前事务已经提交了,可以访问该版本

  3. DB_TRX_ID > max_trx_id时,比预分配事务ID大,说明当前事务在ReadView生成后才开始,还没有提交不能访问该版本

  4. min_trx_id <= DB_TRX_ID <= max_trx_id 时,如果DB_TRX_ID不在m_ids中,即当前事务已经提交了,可以访问该版本。

看完这些规则我们可以总结以下规律:

  1. 当前事务可以读取自己更改的记录,对应第一条规则
  2. 只有一个事务提交了,才能去读取该事务ID下的版本记录(保证事务的隔离性,防止脏读),对应第二、三、四条规则

3.MVCC的执行流程

这里承接第二部分举过的案例,来具体分析事务5在不同隔离级别两次查询id为10的记录时,分别会读取哪个版本的数据。学会这个案例之后,就能理解MVCC如何解决不可重复读幻读的问题。

RC隔离级别

在RC隔离级别下,事务每一次执行快照读时都会生成一次ReadView。

在第一次查询时,还未提交的事务有3、4、5,那么m_ids(活跃事务ID集合)为{3,4,5},min_trx_id(最小活跃事务ID)为3,max_trx_id(预提交事务ID)为5+1=6,creator_trx_id(事务创建者ID)为5。

在第二次查询时,还未提交的事务有4、5,那么m_ids(活跃事务ID集合)为{4,5},min_trx_id(最小活跃事务ID)为4,max_trx_id(预提交事务ID)为5+1=6,creator_trx_id(事务创建者ID)为5。

RR隔离级别

在RR隔离级别下,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。

在第一次查询时,还未提交的事务有3、4、5,那么m_ids(活跃事务ID集合)为{3,4,5},min_trx_id(最小活跃事务ID)为3,max_trx_id(预提交事务ID)为5+1=6,creator_trx_id(事务创建者ID)为5。

在第二次查询时,直接复用ReadView。

读取版本记录

在读取版本记录时,需要根据DB_TRX_ID匹配ReadView的读取规则,判断当前记录对DB_TRX_ID对应的事务是否可见,如果可见,直接读取当前版本,如果不可见,则读取前一个undo log记录继续进行匹配。

我们以第一个ReadView举例,当前undo log版本链和读视图如下:

当DB_TRX_ID为4,存在于活跃事务列表中,因此不可以读取该行数据,需要向前找DB_TRX_ID为3的记录。

当DB_TRX_ID为3时,同样存在于活跃事务列表,因此不可以读取该行数据,需要向前找DB_TRX_ID为2的记录。

当DB_TRX_ID为2时,发现DB_TRX_ID<min_trx_id,符合规则,因此可以读取该行记录。

最后的读取结果为:

1020Jack20x00001

4.MVCC小结

MVCC解决不可重复读

RC隔离级别

在RC读取已提交下,事务每一次执行快照读时都会生成一次ReadView,这也就造成了每次读取就有不同 ReadView,那么就会读到已提交的事务修改的内容,不能解决不可重复读的问题。

RR隔离级别

解决 RR 不可重复读主要靠 Readview,在隔离级别为可重复读时,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。由于后续复用了 ReadView,所以数据对当前事务的可见性和第一次是一样的,所以从 undo log 中读到的数据快照和第一次是一样的,即便过程中有其他事务修改也读不到。因此解决了不可重复读的问题。

MVCC解决幻读

InnoDB存储引擎在 RR 级别下通过 MVCCNext-key Lock(临键锁) 来解决幻读问题:

1、执行快照读

快照读的情况下,RR 隔离级别使用MVCC,只会在事务开启后的第一次查询生成 Read View ,并使用至事务提交。所以在生成 Read View 之后其它事务所做的更新、插入记录版本对当前事务并不可见,实现了可重复读和防止快照读下的 “幻读”。

2、执行当前读

、执行快照读**

快照读的情况下,RR 隔离级别使用MVCC,只会在事务开启后的第一次查询生成 Read View ,并使用至事务提交。所以在生成 Read View 之后其它事务所做的更新、插入记录版本对当前事务并不可见,实现了可重复读和防止快照读下的 “幻读”。

2、执行当前读

当前读的情况下,读取的都是最新的数据,如果其它事务有插入新的记录,并且刚好在当前事务查询范围内,就会产生幻读。InnoDB 使用Next-key Lock来防止这种情况。当执行当前读时,会锁定读取到的记录的同时,锁定它们的间隙,防止其它事务在查询范围内插入数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1971085.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一天攻克一个知识点 —— 设计模式之动态代理

一、设计模式之代理设计 代理设计是在Java开发中使用较多的一种设计模式&#xff0c;所谓的代理设计模式就是指一个代理主体操作真实主体&#xff0c;真实主体操作具体业务&#xff0c;代理主体负责给具体业务添砖加瓦。 就好比在生活中你有一套房子想要出租(你真实主体)&…

Mysql-窗口函数一

文章目录 1. 窗口函数概述1.1 介绍1.2 作用 2. 场景说明2.1 准备工作2.2 场景说明2.3 分析2.4 实现2.4.1 非窗口函数方式实现2.4.2 窗口函数方式实现 3. 窗口函数分类4. 窗口函数基础用法&#xff1a;OVER关键字4.1 语法4.2 场景一 :计算每个值和整体平均值的差值4.2.1 需求4.2…

免费的远程办公软件

产生背景 我们的SD-WAN组网的产品一直都是以CPE盒子的形式进行交付&#xff0c;如果您有多个企业分支&#xff0c;那么需要在每个分支安装一个CPE盒子。 这种形式存在一些问题&#xff1a; 成本过高&#xff0c;CPE盒子本身是有成本的&#xff0c;没办法做到免费使用&#xf…

用Maven构建项目和管理依赖

运行本篇中的代码&#xff1a;idea专业版或者idea社区版本&#xff08;2021.1~2022.1.4&#xff09; 用Maven构建项目和管理依赖 1. 初见maven2. maven在网站项目中的应用3. maven和idea的关系4. maven的使用4.1 项目构建4.11 在idea创建maven项目4.12 利用maven命令打包项目 4…

“QtGraphicalEffects“ is not installed

【1】问题&#xff1a;qml项目报 module "QtGraphicalEffects" is not installed 【2】解决方法&#xff1a;将qml目录中的"QtGraphicalEffects" 拷贝到工程release目录

3种 Ajax 方式:原生、jQuery、axios

毋庸多言&#xff0c;Ajax 技术在网页中是划时代的进步。学会它&#xff0c;可以说掌握了一招半式&#xff0c;不再是门外汉了。 这里将 3 种 Ajax 方式一并呈上。 感谢 https://run.uv.cc/ 平台&#xff0c;以及 /api 接口 https://andi.cn/page/621639.html https://andi…

用Java手写jvm之模拟类加载器加载class

写在前面 本文来尝试模拟类加载器加载class的过程。 1&#xff1a;程序 首先来定义类加载器类&#xff1a; /*** 类加载器* 正常应该有bootstrap&#xff0c;ext&#xff0c;app三个类加载器&#xff0c;这里简单起见&#xff0c;只用一个来模拟了*/ public class ClassLoa…

入门 PyQt6 看过来(案例)20~ 动态树

​ 1 QTreeWidget树类 QTreeWidget类可以呈现数组、数列等数据&#xff0c;并且可以进行交互&#xff0c;它使用标准的数据模型&#xff0c;其单元格数据通过QTableWidgetItem对象来实现。 QTreeWidget继承自QTreeView&#xff0c;是封装了默认Model的QTreeView&#xff0c;其…

C++ | Leetcode C++题解之第312题戳气球

题目&#xff1a; 题解&#xff1a; class Solution { public:int maxCoins(vector<int>& nums) {int n nums.size();vector<vector<int>> rec(n 2, vector<int>(n 2));vector<int> val(n 2);val[0] val[n 1] 1;for (int i 1; i &l…

ElasticSearch入门(六)SpringBoot2

private String author; Field(name “word_count”, type FieldType.Integer) private Integer wordCount; /** Jackson日期时间序列化问题&#xff1a; Cannot deserialize value of type java.time.LocalDateTime from String “2020-06-04 15:07:54”: Failed to des…

Django文件上传

【图书介绍】《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》_django 5企业级web应用开发实战(视频教学版)-CSDN博客 《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) 本节主要介…

【计算机网络】IP地址和子网掩码(子网掩码篇)

个人主页:【😊个人主页】 系列专栏:【❤️计算机网络】 文章目录 前言什么是子网掩码?子网掩码的组成组成规则表示方法子网掩码的分类标准(默认)子网掩码:变长子网掩码(VLSM):全零和全一子网掩码:子网掩码的计算确定IP地址类别及默认子网掩码计算子网掩码根据子网数…

橙单中台化低代码生成器

​橙单中台化低代码生成器 在当今快速发展的软件开发领域&#xff0c;橙单中台化低代码生成器凭借其强大的功能和灵活的架构&#xff0c;成为了开发者不可或缺的利器。本文将介绍橙单的基本信息、特点以及如何快速部署和使用。 软件简介 橙单中台化低代码生成器是一款开源的低…

被华为的AI扩图震惊到,超自然超好看!

美颜、P图对大家来说都不陌生&#xff0c;但是近期在互联网实火的各种AI扩图你了解多少&#xff1f;它既能满足图片构图时进行延伸美化&#xff0c;又能在未知的创意里无限探索。 近期&#xff0c;华为Pura 70系列手机获推HarmonyOS 4.2.0.172 更新&#xff0c;华为Pura 70 Pr…

事务性邮件API的功能优势?考虑哪些指标?

事务性邮件API的性能如何优化&#xff1f;怎么选择邮件API接口&#xff1f; 在当今数字化时代&#xff0c;企业需要一种高效、可靠的方法与客户沟通。事务性邮件API成为解决这一需求的重要工具。AokSend将探讨事务性邮件API的功能优势及考虑的关键指标。 事务性邮件API&#…

如何在 Kubernetes 中使用 ClickHouse 和 JuiceFS

ClickHouse 结合 JuiceFS 一直是一个热门的组合&#xff0c;社区中有多篇实践案例。今天的文章来自美国公司 Altinity&#xff0c;一家提供 ClickHouse 商业服务的企业&#xff0c;作者是 Vitaliy Zakaznikov&#xff0c;他尝试了这个组合并公开了过程中使用的代码。原文有两篇…

基于DreamBooth的“妙鸭相机”——一次不太成功的实践

重磅推荐专栏: 《大模型AIGC》 《课程大纲》 《知识星球》 本专栏致力于探索和讨论当今最前沿的技术趋势和应用领域,包括但不限于ChatGPT和Stable Diffusion等。我们将深入研究大型模型的开发和应用,以及与之相关的人工智能生成内容(AIGC)技术。通过深入的技术解析和实践经…

Encoder-Decoder:Seq2seq

目录 一、编码器解码器架构&#xff1a;1.定义&#xff1a;2.在CNN中的体现&#xff1a;3.在RNN中的体现&#xff1a;4.代码&#xff1a; 二、Seq2seq&#xff1a;1.模型架构&#xff1a;1.1编码器&#xff1a;1.2解码器&#xff1a; 2.架构细节&#xff1a;3.模型评估指标BLEU…

C# Unity 补全计划 泛型

本文仅作学习笔记与交流&#xff0c;不作任何商业用途&#xff0c;作者能力有限&#xff0c;如有不足还请斧正 1.什么是泛型 泛型&#xff08;Generics&#xff09;是C#中的一个强大特性&#xff0c;允许你编写可以适用于多种数据类型的可重用代码&#xff0c;而不需要重复编写…

第二证券:刚刚!亚太股市,跌麻了!

今天早盘&#xff0c;亚太股市全线崩跌。日经225指数在大幅低开之后快速下行&#xff0c;最大跌幅近5%&#xff1b;韩国、澳大利亚股指亦迎来逾越2%以上的暴降。那么&#xff0c;毕竟发生了什么&#xff1f; 剖析人士认为&#xff0c;或许仍是与日元套息有关。从前史来看&…