【MySQL】MVCC是如何解决快照读下的幻读问题的

文章目录

  • LBCC
    • 当前读
  • MVCC
    • 隐藏列
    • undo log
    • Read View
  • 总结

我们从上文中了解到InnoDB默认的事务隔离级别是repeatable read(后文中用简称RR),它为了解决该隔离级别下的幻读的并发问题,提出了LBCCMVCC两种方案。其中LBCC解决的是当前读情况下的幻读,MVCC解决的是普通读(快照读)的幻读。至于什么是当前读,什么是快照读,将在文中给出答案。

有想赚点外块|技术交流的朋友,欢迎来撩

LBCC

LBCCLock-Based Concurrent Control的简称,意思是基于锁的并发控制,此文主要内容是MVCC,所以LBCC暂时不展开。

当前读

当前读(Locking Read)也称锁定读,读取当前数据的最新版本,而且读取到这个数据之后会对这个数据加锁,防止别的事务更改即通过next-key锁(行锁+gap锁)来解决当前读的问题。

在进行写操作的时候就需要进行“当前读”,读取数据记录的最新版本,包含以下SQL类型:select ... lock in share modeselect ... for updateupdatedeleteinsert

因为锁的粒度过大,会导致性能的下降,因此提出了比LBCC性能更优越的方法MVCC

MVCC

MVCCMulti-Version Concurremt Control的简称,意思是基于多版本的并发控制协议,通过版本号,避免同一数据在不同事务间的竞争,只存在于InnoDB引擎下。它主要是为了提高数据库的并发读写性能,不用加锁就能让多个事务并发读写。

MVCC的实现依赖于:三个隐藏字段、Undo logRead View,其核心思想就是:只能查找事务id小于等于当前事务ID的行;只能查找删除时间大于等于当前事务ID的行,或未删除的行。

接下来让我们从源码级别来分析下MVCC

隐藏列

MySQL中会为每一行记录生成隐藏列,接下来就让我们了解一下这几个隐藏列吧。

(1)DB_TRX_ID:事务ID,是根据事务产生时间顺序自动递增的,是独一无二的。如果某个事务执行过程中对该记录执行了增、删、改操作,那么InnoDB存储引擎就会记录下该条事务的id。

(2)DB_ROLL_PTR:回滚指针,本质上就是一个指向记录对应的undo log的一个指针,大小为 7 个字节,InnoDB 便是通过这个指针找到之前版本的数据。该行记录上所有旧版本,在undo log中都通过链表的形式组织。

(3)DB_ROW_ID:行标识(隐藏单调自增 ID),如果表没有主键,InnoDB 会自动生成一个隐藏主键,大小为 6 字节。如果数据表没有设置主键,会以它产生聚簇索引。

(4)实际还有一个删除flag隐藏字段,既记录被更新或删除并不代表真的删除,而是删除flag变了。

undo log

每当我们要对一条记录做改动时(这里的改动可以指INSERT、DELETE、UPDATE),都需要把回滚时所需的东西记录下来, 比如:

  • Insert undo log :插入一条记录时,至少要把这条记录的主键值记下来,之后回滚的时候只需要把这个主键值对应的记录删掉就好了。
  • Delete undo log:删除一条记录时,至少要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录插入到表中就好了。
  • Update undo log:修改一条记录时,至少要把修改这条记录前的旧值都记录下来,这样之后回滚时再把这条记录更新为旧值就好了。
    InnoDB把这些为了回滚而记录的这些东西称之为undo log。这里需要注意的一点是,由于查询操作(SELECT)并不会修改任何用户记录,所以在查询操作执行时,并不需要记录相应的undo log

每次对记录进行改动都会记录一条undo日志,每条undo日志也都有一个DB_ROLL_PTR属性,可以将这些undo日志都连起来,串成一个链表,形成版本链。版本链的头节点就是当前记录最新的值。

先插入一条记录,假设该记录的事务id为80,那么此刻该条记录的示意图如下所示
sql插入
实际上insert undo只在事务回滚时起作用,当事务提交后,该类型的undo日志就没用了,它占用的Undo Log Segment也会被系统回收。接着继续执行sql操作
sql更新
其版本链如下
版本链

很多人以为undo log用于将数据库物理的恢复到执行语句或者事务之前的样子,其实并非如此,undo log是逻辑日志,只是将数据库逻辑的恢复到原来的样子。因为在多并发系统中,你把一个页中的数据物理的恢复到原来的样子,可能会影响其他的事务。

Read View

在可重复读隔离级别下,我们可以把每一次普通的select查询(不加for update语句)当作一次快照读,而快照便是进行select的那一刻,生成的当前数据库系统中所有未提交的事务id数组(数组里最小的idmin_id)和已经创建的最大事务idmax_id)的集合,即我们所说的一致性视图readview。在进行快照读的过程中要根据一定的规则将版本链中每个版本的事务idreadview进行匹配查询我们需要的结果。

快照读是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。MVCC只在 READ COMMITTEDREPEATABLE READ两个隔离级别下工作,其他两个隔离级别不和MVCC不兼容。因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据行,而SERIALIZABLE 则会对所有读取的行都加锁。事务的快照时间点(即下文中说到的Read View的生成时间)是以第一个select来确认的。所以即便事务先开始,但是select在后面的事务的update之类的语句后进行,那么它是可以获取前面的事务的对应的数据。

RC和RR隔离级别下的快照读和当前读:RC隔离级别下,快照读和当前读结果一样,都是读取已提交的最新;RR隔离级别下,当前读结果是其他事务已经提交的最新结果,快照读是读当前事务之前读到的结果。RR下创建快照读的时机决定了读到的版本。

对于使用RC和RR隔离级别的事务来说,都必须保证读到已经提交了的事务修改过的记录,也就是说假如另一个事务已经修改了记录但是尚未提交,是不能直接读取最新版本的记录的。核心问题就是:需要判断一下版本链中的哪个版本是当前事务可见的。为此,InnoDB提出了一个Read View的概念。

Read View就是事务进行快照读(普通select查询)操作的时候生产的一致性读视图,在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,它由执行查询时所有未提交的事务id数组(数组里最小的id为min_id)和已经创建的最大事务id(max_id)组成,查询的数据结果需要跟read view做对比从而得到快照结果。

快照规则

版本链比对规则:

  1. 如果落在绿色部分(trx_id<min_id),表示这个版本是已经提交的事务生成的,这个数据是可见的;
  2. 如果落在红色部分(trx_id>max_id),表示这个版本是由将来启动的事务生成的,是肯定不可见的;
  3. 如果落在黄色部分(min_id<=trx_id<=max_id),那就包含两种情况:
    a.若row的trx_id在数组中,表示这个版本是由还没提交的事务生成的,不可见;如果是自己的事务,则是可见的;
    b.若row的trx_id不在数组中,表示这个版本是已经提交了的事务生成的,可见。

光说不练假把式,接下来就让我们用例子来演示一下:首先我们要准备两张表,一张test和一张account表,然后我们以accountundo log来画版本链,准备数据和原始记录图如下

//test表中数据
id=1,c1='11';
id=5,c1='22';
//account表数据
id=1,name=‘lilei’;


如下图,我们将按照里面的顺序执行sql
RR模式下多个事务执行
当我们执行到第7行的select的语句时,会生成readview[100,200],300,版本链如图所示:

此时我们查询到的数据为lilei300。我们首先要拿最新版本的数据trx_id=300readview中匹配,落在黄色区间内,一看该数据已经提交了,所以是可见的。继续往下执行,当执行到第10行的select语句时,因为trx_id=100并未提交,所以版本链依然为readview[100,200],300,版本链如图所示:

此时我们查询到的数据为lilei300。我们按上边操作,从最新版本依次往下匹配,我们首先要拿最新版本的数据trx_id=100readview中匹配,落在黄色区间内,一看该数据在未提交的数组中,且不是自己的事务,所以是不可见的;然后我们选择前一个版本的数据,结果同上;继续向上找,当找到trx_id=300的数据时,会落在黄色区间,且是提交的,所以数据可见。继续往下执行,当执行到第13行的select语句时,此时尽管trx_id=100已经提交了,因为是InnoDB的RR模式,所以readview不会更改,仍为readview[100,200],300,版本链如图所示:

此时我们查询到的数据为lilei300。原因同上边的步骤,不再赘述。

当执行update语句时,都是先读后写的,而这个读,是当前读,只能读当前的值,跟readview查找时的快照读区分开。

刚才演示的是InnoDB下的RR模式,接下来我们简单说一下RC模式,上文中提到的RC模式的数据读都是读最新的即当前读,所以readview是实时生成的,执行语句如图所示:
RC模式下多事务执行
当我们执行到第13行的select的语句时,会生成readview[200],300,版本链还和之前一样,此时我们查询到的数据为lilei2。原因和上边讲的RR模式下的比对规则相同。

此处我们演示的是update的情况,对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制一份,然后将trx_id改成删除操作的trx_id,同时在该条记录的头信息(record header)里的(deleted_flag)标记位上写上true,来表示当前记录已经被删除,在查询时按照上边的规则查到对应的记录,如果delete_flag标记位为true,意味着记录已被删除,则不返回数据。

大家应该还关心一个问题,即undo log什么时候删除呢?

系统会判断,没有比这个undo log更早的read view的时候,undo log会被删除。所以这里也就是为什么我们建议你尽量不要使用长事务的原因。长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。

总结

  • LBCC是基于锁的并发控制,因为锁的粒度过大,会导致性能的下降,因此提出了比 LBCC 性能更优越的方法 MVCC。
  • MVCC 是基于多版本的并发控制协议,通过版本号,避免同一数据在不同事务间的竞争,只存在于InnoDB引擎下。
  • MVCC 主要是为了提高数据库的并发读写性能,不用加锁就能让多个事务并发读写。
  • MVCC的实现依赖于:三个隐藏字段、Undo log和Read View。
  • MVCC 的核心思想就是:只能查找事务id小于等于当前事务ID的行;只能查找删除时间大于等于当前事务ID的行,或未删除的行。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

信号链噪声分析11

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 提示&#xff1a;这里可以添加技术概要 如今的射频(RF)系统变得越来越复杂。高度的复杂性要求所有系统指标&#xff08;例如严格的 链接和噪声预算&#xff09;达到最佳性能。确保整个信号链的正确设计至关重要。而信…

如何了解(海外抖音TiKToK)与国内抖音的区别以及介绍

一、海外抖音TK平台的优势 自从抖音在中国大受欢迎后&#xff0c;海外也推出了海外版抖音TK平台。尽管两者都是视频分享平台&#xff0c;但它们在一些方面具有明显的区别和独特的优势。下面将详细介绍海外抖音TK平台的优势以及与国内抖音的区别性。 优势&#xff1a; 1. 多元…

三防工业平板在哪些行业中得到广泛应用?

随着科技的不断进步&#xff0c;工业平板正逐渐成为各行业中不可或缺的工具。其中&#xff0c;三防工业平板由于其卓越的耐用性和丰富的功能&#xff0c;在许多行业中得到了广泛的应用。本文将重点介绍三防工业平板在以下几个行业中的应用。 三防工业平板在物流行业中发挥着关键…

vue-router.esm.js:2248 Error: Cannot find module ‘@/views/dylife/ 报错解决

具体是展示 一直加载 控制台报找不到模块 webpack版本问题&#xff0c;webpack4 不支持变量方式的动态 import &#xff0c;新版本需要使用 require() 来解决此问题。 return () > import(/views/${view}) 改写成 return (resolve) > require([/views/${view}], reso…

【三层交换机】网络杂谈(16)之三层交换机技术

涉及知识点 什么是三层交换机&#xff0c;三层交换技术的由来&#xff0c;三层交换机&#xff0c;三层交换的应用范例。深入了解三层交换机技术。 原创于&#xff1a;CSDN博主-《拄杖盲学轻声码》&#xff0c;更多内容可去其主页关注下哈&#xff0c;不胜感激 文章目录 涉及知…

HBase(5):导入测试数据集

1 需求 将ORDER_INFO.txt 中的HBase数据集&#xff0c;我们需要将这些指令放到HBase中执行&#xff0c;将数据导入到HBase中。 可以看到这些都是一堆的put语句。那么如何才能将这些语句全部执行呢&#xff1f; 2 执行command文件 2.1 上传command文件 将该数据集文件上传到指…

6.5 指令与文件的搜寻

6.5.1 指令文件名的搜寻 在终端机模式当中&#xff0c;连续输入两次[tab]按键就能够知道使用者有多少指令可以下达。 which &#xff08;寻找“可执行文件”&#xff09; 这个指令是根据“PATH”这个环境变量所规范的路径&#xff0c;去搜寻“可执行文件”的文件名。所以&…

DETR系列:RT-DETR(一) 论文解析

论文&#xff1a;《DETRs Beat YOLOs on Real-time Object Detection》 2023.4 DETRs Beat YOLOs on Real-time Object Detection&#xff1a;https://arxiv.org/pdf/2304.08069.pdf 源码地址&#xff1a;https://github.com/PaddlePaddle/PaddleDetection/tree/develop/conf…

【Visual Studio】报错 ASSERT: “i >= 0 i < size()“,使用 C++ 语言,配合 Qt 开发串口通信界面

知识不是单独的&#xff0c;一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏&#xff1a;Visual Studio。 这个 Bug 是我做这个工程时遇到的&#xff1a;【Visual Studio】Qt 的实时绘图曲线功能&#xff0c;使用 C 语言&#xff0c;配合 Qt 开发串口通信界面。 文…

javaweb学习2

p标签使用 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <!--p标签定义段落 p元素自动在其前后创建一段空白--> hello&#xff0c;world &l…

设计模式之访问者模式笔记

设计模式之访问者模式笔记 说明Iterator(访问者)目录访问者模式示例类图抽象访问者角色类抽象元素角色类宠物猫类宠物狗类自己类其他人类家类测试类 说明 记录下学习设计模式-访问者模式的写法。JDK使用版本为1.8版本。 Iterator(访问者) 意图:表示一个作用于某对象结构中的…

日历组件 el-calendar 实现标记功能

需求&#xff1a;在日历组件中选择月份时&#xff0c;可以显示当月已经质检或需质检的数据 思路&#xff1a;前端每次点击日期选择器的时候调用接口&#xff0c;接口返回当月需要质检或已质检的数据&#xff0c;前端拿到数据就开始做判断然后回显。 大体样式 代码&#xff1a…

Redis7【① 概述 安装 配置】

1. Redis入门概述 1. Redis是什么 Redis全称 远程字典服务器&#xff08;Remote Dictionary Server&#xff09;&#xff0c;它是完全开源的&#xff0c;使用ANSIC语言编写遵守BSD协议&#xff0c;是一个高性能的基于内存的Key-Value数据库&#xff0c;提供了丰富的数据结构&…

windows无法启动RemoteDesktopServices服务(位于本地计算机上)。错误126:找不到指定的模块。

win10的搜索栏输入 注册表编辑器。打开&#xff0c;找到如下路径 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TermService\Parameters 将指定数值项ServiceDll的数值数据改成默认值&#xff1a; %SystemRoot%\System32\termsrv.dll 再重新尝试就好了。 …

Spring是什么?

目录 1、Spring的简介 2、Spring七大功能模块 3、Spring的优点 4、Spring的缺点 5、Sprig容器 6、Spring的生态圈&#xff08;重点&#xff09;***** 7、Spring中bean的生命周期 1、Spring的简介 Spring的英文翻译为春天&#xff0c;可以说是给Java程序员带来了春天&…

DAMA数据治理CDGA/CDGP认证考试备考经验分享

一&#xff0c;关于DAMA中国和CDGA/CDGP考试 国际数据管理协会&#xff08;DAMA国际&#xff09;是一个全球性的专业组织&#xff0c;由数据管理和相关的专业人士组成&#xff0c;非营利性机构&#xff0c;厂商中立。协会自1980年成立以来&#xff0c;一直致力于数据管理和数字…

Baumer工业相机堡盟工业相机如何通过BGAPISDK设置多帧采集模式(C#)

Baumer工业相机堡盟工业相机如何通过BGAPISDK设置多帧采集模式&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机BGAPISDK和多帧采集模式的技术背景Baumer工业相机通过BGAPISDK设置多帧采集模式功能1.引用合适的类文件2.通过BGAPISDK设置多帧采集模式功能 Baumer工业相…

Wolfram Mathematica 13.3 特别版

WOLFRAM MATHEMATICA 全球現代技術計算的權威系統 MATHEMATICA 三十年來&#xff0c;Mathematica 定義了技術計算領域的最新技術—並為全球數百萬創新者、教育工作者、學生和其他人提供了主要的計算環境。 Mathematica 以其卓越的技術和簡易實用廣受讚譽&#xff0c;提供了單…

13.RocketMQ之消息的存储与发送

1. 消息存储 1.1 消息存储 分布式队列因为有高可靠性的要求&#xff0c;所以数据要进行持久化存储。 消息生成者发送消息Broker收到消息&#xff0c;将消息进行持久化&#xff0c;在存储中新增一条记录返回ACK给生产者Broker消息给对应的消费者&#xff0c;然后等待消费者返回A…

【MOOC 作业】第5章 链接层

不是标答也不是参考答案 仅从个人理解出发去做题 1、(20分) 在某网络中标识为 A 到 E 的 5 个结点以星形与一台交换机连接&#xff0c;考虑在该网络环境中某个正在学习的交换机的运行情况。假定&#xff1a;该交换机表初始为空。B 向 E 发送一个帧&#xff0c;此时交换机将该数…