数据库 MVCC 详解

目录

1. 什么是 MVCC?

2. MVCC 的好处?

3. 快照读?当前读分别是什么?怎么理解?

3.1 快照读

3.2 当前读

4.  MVCC 实现原理

4.1 隐藏字段

4.2 undo log(版本链)

4.3 readView

5. readView 深层详解

6. 数据库的四种隔离级别

7. 读已提交和可重复读的区别?

7.1 MVCC 主要作用体现在读已提交和可重复读两种隔离级别下

7.2 MVCC 在读已提交隔离级别中的实现原理

7.3 MVCC 可重复读隔离级别中的实现原理

7.4 再次提醒

8. MVCC 是如何实现读已提交的?

8. MVCC 可重复读是如何解决不可重复读的?

9. 间隙锁解决幻读问题(补充点)


1. 什么是 MVCC?

MVCC 英文全称叫 "Multi Version Concurrency Control",翻译过来就是 "多版本并发控制"。在 MySQL 众多存储引擎中只有 InnoDB 存储引擎中实现了 MVCC 机制。

2. MVCC 的好处?

首先我们要清楚,在 InnoDB 存储引擎下,假设事务A我们对一行数据进行修改操作,是会对这一行数据进行加写锁的(也就是我们所说的行锁);如果此时事务B来查询这一行数据,它就要加读锁,读锁与写锁冲突,所以事务B加锁不成功,它就必须等待事务A操作执行完毕释放写锁之后才能去进行读操作。

而有了 MVCC 的加入,我们的事务B再去查询该行数据时,就不需要等待事务A释放锁可以直接查询,查询方式是快照读(下面会解释到),而且查询到的是事务A修改数据之前当前行的数据,提高了数据库的并发效率。

总之一句话:MVCC 是通过数据行的多版本管理来实现数据库的并发控制,提高数据库的并发性能。

3. 快照读?当前读分别是什么?怎么理解?

3.1 快照读

我们姑且把刚才的事务A的查询操作理解为写操作,事务B的查询操作理解为读操作;在 MVCC 下,这里的读指的是快照读。了解在 Linux 操作系统和 Git 代码管理的大致应该清楚,我们可以通过 Linux 操作系统的快照将系统回溯到之前的某个版本,Git 也可以通过回溯版本返回至之前的某个代码版本。MVCC 中的快照与这两者大致意思相近,可以类比理解。

数据在修改之前和修改之后版本是不一样的,我们读取别人正在操作的数据时,可以读取该数据操作之前的快照,就可以避免读写锁互斥导致阻塞等待这一现象。

3.2 当前读

当前读就很好理解了,没有 MVCC 时,数据库是靠加锁来避免数据安全性问题,加的锁都是悲观锁。共享锁,排它锁都属于是当前读的一种范畴。

我们去读取数据,读取到的一定是当前数据,没有数据版本这一说法。假设要去读一个正在被修改的数据,是会阻塞的,只有别人修改完,才能去执行当前读这一操作,也可以理解为同步读。

4.  MVCC 实现原理

MVCC 实现原理主要依赖于三部分,隐藏字段,undo log版本链,readView。

4.1 隐藏字段

对于 InnoDB 存储引擎的表来说,它的聚簇索引记录(理解为每行数据即可)中都会有两个必要的隐藏字段 trx_id(事务id) 和 roll_pointer(回滚指针)。没有主键的表会有第三个额外的隐藏主键字段。隐藏字段的主要作用就是对每次数据操作进行标记区分并记录操作之前的数据的地址。

我就以下面这幅图来给各位解析一下 trx_id 和 roll_pointer.

trx_id:每次一个事务对聚簇索引的记录做改动,都会把该事务的事务id赋值给隐藏字段。

roll_pointer:每次对聚簇索引的记录做改动时,都会把旧的版本写入到 undo 日志中去,然后这个隐藏列相当于一个指针,可以通过它来找到该记录修改之前的数据。

如上图,假设与四个事务A,B,C,D。事务A插入数据,事务B,C,D均对插入的数据做了修改。四个事务在对数据进行增删改查的时候,数据库就会给这四个事务的隐藏字段 trx_id 以自增的方式赋值,这里 假设分别赋值为 1,2,3,4。

roll_pointer 回滚指针则是指向当前数据修改之前的数据值,倘若事务回滚,就会返回到之前的数据。

4.2 undo log(版本链)

如上所示四个事务进行的四次数据更新操作,每次数据操作之后,数据库都会把操作之前的旧值存放到 undo 日志中记录下来,随着更新次数的增多,每次记录都会由隐藏字段中的 roll_pointer 指针连接起来形成链表,所形成的链表我们就称之为版本链,链表的头节点就是当前数据最新的节点。

4.3 readView

刚才我们说到了版本链,既然一条数据经历了多次操作,有那么多个版本,我们在查询数据并进行操作的时候,是怎么知道该选择哪个版本的数据的呢?一定是查询操作最新的吗?这是不一定的。查询操作哪个版本的数据取决于我们的第三个重要元素 readView。

readView 就是事务在使用 MVCC 机制对数据库中的数据操作时产生的读视图。当事务开启之后,会生成数据库当前系统的一个快照,InnoDB 会为每个事务构建一个数组,用来记录并维护当前系统活跃事务的id (这里的活跃指代的是事务正在操作数据但是没有进行提交)。

5. readView 深层详解

readView 是MVCC 三个中最重要的组成部分,也是面试 MVCC 时经常问道的一个点。

readView 的核心原理主要体现在 READ COMMITTD(读已提交)和 REPEATABLE READ(可重复读) 两种隔离级别上。

READ COMMITTD:在每次进行 SELECT 查询操作的时候都会去生成一个 readView;

REPEATABLE READ:每开启一个事物才会生成一个 readView,一个事务的所有SQL语句共享一个 readView。

readView 有多个属性,m_ids 就可以理解为生成的数组记录,如下图所示,基于以下几种属性, 一共有四种可能情况。

情况一  trx_id == creator_trx_id:说明这条记录就是当前事务插入所形成的,自己插入的数据自己肯定可以访问;

情况二 trx_id < min_trx_id:    min_trx_id表示的是正在活跃的事务最小的 id,而所有活跃的事物都是未提交的,所以就可以查询得到,不会出现读未提交的情况;

情况三 trx_id > max_trx_id:   max_trx_id表示要分配给下一个事务的 id,二我们要查询的数据的 id 却比待分配的事物的 id 还要大,这是不可能查得到的。

情况四 min_trx_id <= trx_id <= max_trx_id:如果 trx_id 是在m_ids 中,则不可以访问这个版本,因为在此区间内则说明此当前事务正在进行中还没提交,不能访问其他事务未提交的数据,否则可能会产生脏读。如果不在m_ids  中,说明当前事务已经是 commit 提交过了的,则可以访问。

6. 数据库的四种隔离级别

数据库有四种隔离级别。它们的隔离级别由低到高,并发能力由高到低。

读未提交:解决了脏写问题;

读已提交:解决了脏写,脏读问题;

可重复读:解决了脏写,脏读,不可重复读;

串行化:    解决了脏写,脏读,不可重复读,幻读所有问题;

7. 读已提交和可重复读的区别?

7.1 MVCC 主要作用体现在读已提交和可重复读两种隔离级别下

原因:通过上面 MVCC 的简单解释不难看出,MVCC 的核心主要是版本链,而在读未提交的隔离级别下,我们的事务可以读取到其他事务未提交的数据,也就是当前数据的最新状态,不存在版本这一说法,并发效率最高,数据准确度最差;而在串行化隔离级别下,它是加锁不允许两个事务操作同一份数据,也不存在版本链这一说法,并发效率最低,数据准确度最可靠;

7.2 MVCC 在读已提交隔离级别中的实现原理

在 MVCC 读已提交的隔离级别下,它生成 readView 的时机是每进行一次 SELECT 查询就生成一个 readView,如果一个事务中进行了多次 SELECT 查询操作,它就会生成多个 readView 。

7.3 MVCC 可重复读隔离级别中的实现原理

在 MVCC 中 可读已提交的隔离级别下,它生成 readView 的时机是每开启一个事务才会生成一个 readView,如果一个事务中有多个 SELECT 查询操作们还是只会生成一个 readView ,一个事务的所有查询操作共享一个 readView 。

7.4 再次提醒

一定一定要区分好读已提交和可重复读隔离级别下 readView 的生成时机,这是这两种隔离级别原理最最最核心的因素。再次强调!!!

8. MVCC 是如何实现读已提交的?

如下所示是 student 学生表中的一条数据

(1) 假设现在有事务A和事务B两个事务并发操作该行数据。事务A执行了两次查询操作,事务B执行了一次更新操作;

(2)事务A执行第一次查询操作,先生成 readView ,我们姑且称之为 readView_1,还未开始查询操作,事务B率先执行了更新操作,将数据进行了修改并提交,事务B结束,此时事务A第一次查询开始,但由于事务A已经生成了 readView_1 ,所以它不会读取到事务B修改过后的数据,读取到的是 readView_1 中事务B修改之前的数据,解决了脏读的问题;

(3)然后,事务A进行第二次查询操作。注意!!!这里它又生成了一个 readView,我们称之为 readView_2,此时的 readView_2 中的数据是已经被事务B修改后的数据了,事务A再次进行查询,发现查询到的数据和刚操第一次查询到的不一样了,就产生了不可重复读的问题。

(4)所以说,MVCC 在读已提交隔离级别下只解决了脏读的问题,没有解决不可重复读的问题。

8. MVCC 可重复读是如何解决不可重复读的?

仍以上面的学生表举例,如下所示

(1)假设现在事务A与事务B并发操作来查询 student 表。事务A 执行SELECT查询操作,执行查询操作之前会生成一个 readView,我们姑且称之为 readView_1 ,事务A从始至终使用的都是 readView_1;

(2)此时事务B来修改 student 数据,可重复读隔离级别中一个事务生成一个 readView ,所以事务B也生成了一个 readView ,我们称之为 readView_2,然后事务B率先修改完毕并提交;

(3)事务A在事务B提交之后才进行的查询,按道理来说因为事务B修改了数据,我们会产生不可重复读,但是因为事务A从始至终都是用的 readView_1 ,所以 事务A在进行查询操作的时候,查询到的其实还是事务B修改之前的数据,由此就解决了不可重复读;而且即便事务A后续进行了多次 SELECT 查询操作,仍然使用最开始生成的 readView,解决了 不可重复读的问题。

(4)总结:其实归根结底,读已提交,可重复读两种隔离级别最关键的因素就是 readView 生成的时机不同,造就了它们不同的隔离级别。

9. 间隙锁解决幻读问题(补充点)

刚才我已经解释过了 MVCC 中是如何解决不可重复读问题的,在 InnoDB 存储引擎中,幻读的问题也得到了解决,解决的方式是利用间隙锁;

还以下面这幅图举例说明

假设事务A与事务B并发执行,事务A要查询 id > 1的用户数据,那么在查询之前,数据库会对 id = 1 之后的区间加上间隙锁,也就是说在事务A执行期间,其他线程不可以在 id > 1 之后插入数据;当有其他操作想要插入数据时,会阻塞等待,只有事务A执行完毕释放了间隙锁,其他线程或者说事务才能进行插入操作,由此就避免了幻读的产生。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业架构LNMP学习笔记49

Redis数据持久化操作&#xff1a; 数据、持久化&#xff08;数据在服务或者软件重启之后不丢失&#xff09;。 如果数据只存储在内存中&#xff0c;肯定会丢失&#xff0c;实现持久化&#xff0c;就需要把数据存储在磁盘中&#xff08;hdd ssd&#xff09;。 memcached在宕机…

数据集笔记:Beijing-BRT-dataset

XMU-smartdsp/Beijing-BRT-dataset (github.com) 1 数据集介绍 这个数据集包含1,280张图片&#xff0c;标注了16,795名行人&#xff0c;用于人群分析。使用720张图片进行训练&#xff0c;560张图片进行测试。名为"frame"的文件夹包含人群图像。 名为"ground_t…

AB试验(三)一次试验的规范流程

AB试验&#xff08;三&#xff09;一次试验的规范流程 一次完整且规范的A/B试验可参考下图&#xff1a; 确定目标和假设 核心&#xff1a;A/B测试是因果推断&#xff0c;所以我们首先要确定原因和结果。目标决定了结果&#xff0c;而假设又决定了原因。 如何确定 分析问题&am…

【适用于电力系统和音频系统】计算信号的总谐波失真 (THD)(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

深眸科技迭代深度学习算法,以AI机器视觉技术扩围工业应用场景

智能制造是制造业数智化转型升级的发展方向&#xff0c;在当前以高端装备制造为核心的工业4.0时代背景下&#xff0c;越来越多的制造企业意识到机器视觉对于提高效率、降低成本&#xff0c;从而提升企业效益的意义。 目前&#xff0c;机器视觉已成为制造业迈向智能制造过程中极…

激光焊如何更准更稳?维视智造激光焊视觉解决方案助力精密制造

激光焊接是一种高能密度、非接触的焊接技术&#xff0c;它利用激光束对工件进行加热和熔化&#xff0c;然后使其在熔池的情况下形成连接。与传统的焊接方法相比&#xff0c;激光焊具有高密度、熔深小、变形小、焊缝质量高、适用性广、自动化程度高等特点&#xff0c;可以实现焊…

【VisualStudio】NuGet包管理器下载缓存packages文件夹过大怎么清理

使用Visual Studio 开发工具时间长了&#xff0c;会发现整个项目的总大小越来越大&#xff0c;默认是存放在电脑系统盘里的&#xff0c;随着Windows11系统常常更新重启&#xff0c;导致系统盘闲置空间越来越小&#xff0c;该怎么办呢。 描述问题 整个解决方案项目会越变越大&…

JVM调优工具

JVM调优工具 Jmap 查看类信息 此命令可以查看内存信息&#xff0c;实例个数以及占用内存大小。 num&#xff1a;序号instances&#xff1a;实例数量bytes&#xff1a;占用空间大小class name&#xff1a;类名称&#xff0c;[C is a char[]&#xff0c;[S is a short[]&#…

Powdersigner + PostgreSql 同步表结构到pg数据库

要用Powdersigner同步表结构到PostgreSql数据库&#xff0c; Powdersigner 版本是 16.5&#xff0c;当前模型是mysql的 1&#xff0c;修改当前模型内容为postgresql的 Database --> Change Current DBMS 选择PostgreSQL 最大版本的&#xff08;因为Powdersigner内置版本一…

Python实现查询一个文件中的pdf文件中的关键字

要求&#xff0c;查询一个文件中的pdf文件中的关键字&#xff0c;输出关键字所在PDF文件的文件名及对应的页数。 import os import PyPDF2def search_pdf_files(folder_path, keywords):# 初始化结果字典&#xff0c;以关键字为键&#xff0c;值为包含关键字的页面和文件名列表…

chrome实用插件分享

colorzilla&#xff08;网页取色器&#xff09; 滴管取色 可以自动获取网页上任何像素或区域的颜色&#xff0c;也可以获取浏览器外部的颜色。 显示元素信息 显示元素的信息&#xff0c;如标签名称、类、id、大小等。 拾色器面板 类似Photoshop软件上的那些功能。 颜色历史…

Delft3D水动力与泥沙运动模拟

目录 第一部分 Delft3D水动力模型的基本原理 第二部分 构建Delft3D模型的基本流程 第三部分 构建Delft3D水动力模型的网格 第四部分 Delft3D水动力模型的运行和后处理 第五部分 Delft3D泥沙运动模型 第六部分 Delft3D泥沙运动模型举例与练习 第七部分 Delft3D泥沙模型进…

山西电力市场日前价格预测【2023-09-20】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-09-20&#xff09;山西电力市场全天平均日前电价为334.70元/MWh。其中&#xff0c;最高日前电价为391.75元/MWh&#xff0c;预计出现在19: 15。最低日前电价为277.77元/MWh&#xff0c;预计…

如何使用IP归属地查询API来追踪网络活动

引言 在当今数字化世界中&#xff0c;了解网络活动的源头和位置对于网络安全、市场研究和用户体验至关重要。IP归属地查询API是一种强大的工具&#xff0c;可以帮助您追踪网络活动并获取有关IP地址的重要信息。本文将探讨如何使用IP归属地查询API来追踪网络活动&#xff0c;以…

基于HOG特征提取和GRNN神经网络的人脸表情识别算法matlab仿真,测试使用JAFFE表情数据库

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 1.HOG特征提取 2.GRNN神经网络 3.JAFFE表情数据库 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 .....................................…

HI_NAS linux 记录

dev/root 100% 占用解决记录 通过下面的命令查看各文件夹 大小 sudo du --max-depth1 -h # 统计当前文件夹下各个文件夹的大小显示为M 最终发现Var/log 占用很大空间 发现下面两个 log 占用空间很大&#xff0c;直接 rm-rf 即可 HI NAS python3 记录 # 安装pip3 sudo apt u…

你真的知道GET和POST两种基本请求方法的区别吗?

GET和POST是HTTP请求的两种基本方法&#xff0c;要说它们的区别&#xff0c;接触过WEB开发的人都能说出一二。 最直观的区别就是GET把参数包含在URL中&#xff0c;POST通过request body传递参数。 你可能自己写过无数个GET和POST请求&#xff0c;或者已经看过很多权威网站总结出…

Linux文件管理命令

Linux命令行 命令空格参数(可写可不写)空格文件(可写可不写)ls/opt 根目录下的opt文件夹ls-a 显示所有文件及隐藏文件/optls -l 详细输出文件夹内容 ls -h 输出文件大小(MB...)ls--full-time 完整时间格式输出ls-d 显示文件夹本身信息&#xff0c;不输出内容ls-t 根据最后修改…

怒刷LeetCode的第8天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一&#xff1a;双指针和排序 ​编辑第二题 题目来源 题目内容 解决方法 方法一&#xff1a;双指针 方法二&#xff1a;递归 方法三&#xff1a;快慢指针 方法四&#xff1a;栈 第三题 题目来源 题目内容 解决方法…

SSM02

SSM02 此时我们已经做好了登录模块接下来可以做一下学生管理系统的增删改查操作 首先&#xff0c;我们应当有一个登录成功后的主界面 在webapp下新建 1.main.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"&…