【MySQL】搞懂mvcc、read view:MySQL事务原理深度剖析

发布时间:2026/10/26 21:25:38

【MySQL】搞懂mvcc、read view:MySQL事务原理深度剖析 前言本节内容是事务里面最难的一部分 就是理解mvcc快照读和read view。这两个部分需要了解隔离性里面的四种隔离级别。 博主之前讲过但是担心友友们不了解 所以这里开头进行了复习。 下面开始我们的学习吧 ps本节内容很难 希望友友们沉下心认真学习哦*目录一致性三种并发方式的安全隐患三个隐藏字段Undo日志mvcc多版本控制read view?RC VS RR的本质区别* *我们先来回忆一下上接内容讲解的隔离性的四种隔离级别 以及并发产生的问题 *脏读一个事务在执行中读到另一个事务的更新但是还没有commit的数据 这种情况叫做脏读。 *不可重复读一个事务提交前和提交后 另一个事务select查到的数据结果是不一样的。 也就是说一个事务一直select 结果某一次select的时候 数据突然变了。 *幻读读者读者可能多出来了一条数据就类似于出现了幻觉。 *读未提交 会导致脏读不可重复读 幻读现象。 *读提交 解决了脏读 但是有不可重复读 幻读。 *可重复单独 解决了脏读 不可重复读 但是有些数据库的insert会有幻读现象mysql解决了幻读 *串行化加锁 不进行并发执行 没有上面的问题。一致性— 事务执行的结果必须使数据库从一个一致性状态变到另一个一致性状态。当数据库只包含事务成功提交的结果时数据库处于一种一致性状态。如果系统运行发生中断某个事务尚未完成而被迫中断而改变未完成的事务对数据库所做的修改已被写入数据库此时数据库就处于一种不正确的状态。因此一致性是通过原子性保证的。三种并发方式的安全隐患----------- * 读读并发不存在任何问题不需要并发控制。 * 读写并发有线程安全问题可能造成事务隔离性问题可能遇到脏读幻读不可重复读 * 写写并发有线程安全问题可能会存在更新丢失问题比如第一类更新丢失第二类更新丢失读写并发也就是一个事务在写一个事务在读。要保证读到的是原来的和另一个事务写的不一样。 这个使用的是一种无锁的并发控制MVCC。 * 1、每个事务都要有自己的事务ID可以根据事务的大小来决定事务到来的先后顺序。 * 2、mysqld可能会面临处理多个事务的情况。事务在使用者的角度看来是原子的但是本质上是有过程的。所以就证明事务也有自己的生命周期。一》mysqld要对事务进行管理:先描述再组织。事务在我看来mysqld中一定是对应的一个或者一套结构体对象/类对象 * 3、所以事务也要有自己的结构体。下面我们都在讲解mvcc以及版本链 很重要 很难理解 需要反复观看。三个隐藏字段------ 其实我们之前在建表的时候 mysql也会给我们添加三个默认的隐藏的字段: *DB_TRX_ID:6byte,每一条数据后面都要有一个属性就是DB_TRX_ID,无论是单sql但是我们手动begin起的事务。都算是事务都有自己的事务ID而DB_TRX ID就是最后操作这条数据的事务ID。 *DB_ROLL_PTR:在MySQL中对于某一行数据来说我们要修改他并不是直接就修改了。 mysql要先将数据保存一份然后再改 这样的话我们改完之后我们也知道未来这个字段历史是谁。所以为了保证能够找到这个最后的历史信息就有了这个DB_ROLL_PTR。 *DB_ROW_ID:隐藏的自增ID如果数据库表中没有主键InnoDB会自动以DB_ROW_ID产生一个聚族索引。大小6byteUndo日志------上面的红框框就是操作系统 然后上层就是用户层。里面有我们的mysql的一个buffer pool 然后undo日志就是在这个buffer pool里面。undo log其实就是mysql里面的一段内存缓冲区。作用就是用来记录一些mysql里面事务的回滚操作等。假如现在有一行数据如下这个数据我们知道是在b树的叶子节点上面。这个b树也在buffer pool里面现在有一个事务10 想要对这行数据进行修改 将名字张三改成李四。因为要修改 所以先将这条记录加锁 然后将这条数据记录复制一份到undo log里面然后就开始修改 现存数据name改成李四 事务ID改成10 然后回滚指针指向刚刚拷贝到undo log里面的数据。这就叫做历史版本。最后commit 释放锁。 就行了。 注意这里示例是写写并发 所以串行化 加锁。然后现在又来了一个事务11也要进行修改 要将这个age修改成28. 那么就和上面一样 先拷贝一份数据到undo log里面。然后修改记录所以 我们就有了一个历史版本链 如果未来我们不想修改了 后悔了 就可以把undo log里面的历史数据拿出来。mvcc多版本控制---------我们把上面的版本链 这种多版本控制就叫做mvcc多版本控制。而里面的一个一个的版本的数据 我们就叫做快照。另外undo log是一个临时缓冲区。 他管理的是一个事务内所形成的版本链条。 什么意思 就是说 一个事务里面 我们多次修改多次update才会形成版本链 当事务commit的时候 undo log 就会被清空 也就是free掉。 同样的 delete数据也能形成版本链 因为delete的本质是把改行数据的flag“置为删除。 所以也可以形成版本链。问题是insert可以形成版本链吗——其实insert可以理解为是没有版本链的但是insert对应的数据也要放到undo log里面。但是如果一旦commit 这个insert对应的版本连也就可以被清空了。 而对于undate和delete来说就不一定 因为可能也有其他的事务在访问这一条记录。我们上面说的是update和delete 以及insert。 那么select呢我们知道 update和delete的对象一定是最新数据 历史数据他们没有权限修改。 那么select我们怎么知道我们读取的是最新数据还是历史数据呢 所以就有了当前读和快照读的概念。 *当前读读取最新的记录 就是当前读 增删改都叫做当前读。select也可能当前读。 *快照读读取历史版本就叫做快照读。那么现在再来看我们之前的读写操作。 我们做过实验 看到的是两个事务 一个写一个读。 然后两个事务看到的数据是不同的数据。——就是因为我们的读取 读取的是历史的数据。 而写写的是当前的数据。 两个事务在访问不同的位置 就不需要进行加锁 所以就不会发生并发的问题 我们就可以并发进行读写操作。所以 这就是之前我们为什么能够读写并发的原因所以 隔离性 本质上是数据上的隔离 也是版本上面的隔离。这就是不同的隔离级别让我们看到不同的版本所以 隔离 隔离性本质上使用mvcc实现的我们的事务回滚利用的也是利用mvcc版本控制的。read view---------read view我们讨论的是rc和rr这两种隔离级别。read view就是事务进行快照读操作的时候生产的读视图在该事务执行快照读的那一刻会生成数据库当前的一个快照记录并维护系统当前活跃事务的ID。当每个事务开启时都会被分配给一个ID这个ID是递增的。所以最新的事务的ID更大read view是一个类与事务的关系就类似于进程地址空间和PCB。两个数据结构之间使用指针连接起来。当我们进行快照读的时候对该记录创建一个read view读视图。然后对它填充数据作为条件。 用来判断当前事务能够看到哪个版本的数据既可能是当前数据 也可能是undo log里面的历史数据。下面看一下这个read view结构体 class Readview { private: trx_id_t m_low_limit_id; //高水位大于等于这个ID的事务均不可见。 trx_id_t m_up_limit_id; //低水位 小于这个ID的事务均可见。 trx_id_t m_creator_trx_id; //创建该Read view的事务ID。 ids_t m_ids; //创建视图时的活跃事务id列表。 trx_id_t m_low_limit_no; bool m_closed; //视图是否关闭 //…省略 };上面重要的是两个水位线 , 事务id。m_ids就是当前正在打开的事务id列表。现在一张图我们来理解read view在这张图里面先看已经提交的事务。 已经提交的事务就是说我们当前的事务read view的时候如果当前事务ID和我们看到的版本链里面的事务ID一样 那么就说明我们可以看到这个版本的数据。如果版本链里面的事务ID比m_ids里面最小的事务ID都小 那么也能看到。 因为ID小 代表事务启动的早 那么后启动的事务就应该能看到先启动的事务。再看快照后来的事务我们说low_limit_id是当前事务read view后能看到的最晚启动的一个事务。 那么如果版本链里面的事务大于这个low_limit_id 就不应该看到这个版本的数据。为什么会出现这种情况 因为事务一定有先有后 后来的事务ID一定大然后就是看正在操作的事务 这里要注意的是正在操作的事务不一定是连续的。 因为虽然我们说ID是递增的 但是事务的执行时间是不同的 有的事务很快就跑完了 有的事务很慢才能跑完。 所以就会出现图中的情况。 而我们形成快照后m_ids里面的版本如果和某个版本的数据相同就说明这个ID的事务还是活跃的 没有commit那么就不能看到。如果没有 那么就能看到。另外我们还要注意的是read view是事务可见性的一个类不是事务创建出来 就有read view 而是这个已经存在的事务 首次进行快照读的时候mysql形成read viewRC VS RR的本质区别-------------有了上面的read view的知识点之后 我们就能谈RC和RR的本质区别了。我们谈论RC和RR的区别 需要使用一个例子 现在我们做几个实验。 首先第一个实验这是account表。 并且此时的隔离级别是可重复读。然后我们两边都开启事务然后两边都进行快照读 记录当前的read view接下来我们左边修改数据然后commit然后我们查一下右边很显然 因为是可重复读 所以数据没有变化。 这也符合我们的预期。现在我们来看一下实验二同样是隔离级别为可重复读。 但是这次右边不进行快照读。 而是等到左边commit之后在进行快照读查右边我们会发现 id 4这个字段被修改了。 也就是说我们的右边看到了左边的修改。 这里为什么会发生这种情况 是因为我们的read view是在快照读的时候就生成 然后RR隔离界别的read view只会生成一次。 就是第一次快照读的时候。 所以在第一个实验中 我们一开始就使用了快照读。 此时m_ids显示左右两个事务都是活跃事务 那么我们进行判断的时候 右边的事务对于左边事务修改的版本就看不见。 实验二的时候 我们一开始没有快照读 而是等到左边事务commit后才进行快照读。那么右边事务的m_ids里面就一定没有左边事务的ID 并且因为左边事务启动在右边事务快照读之前所以左边事务的事务ID也不可能比右边事务的事务的low_limt_id大。 那么这个时候左边事务的事务ID只有两种情况一种情况是比右边事务的up_limit_id还要小。或者是在up_limit_id和low_limit_id之间但是没在m_ids里面。 这两种情况下右边事务都可以看到左边事务的修改版本所以右边事务就能看到左边事务的修改数据版本 上面是RR。RC就好说了RR是只能生成一次read view 只能进行一次快照。 后面的事务无论做什么修改 都要根据这一个快照进行判断能不能够看到这些版本数据。 但是RC每次进行快照读都能生成快照 每次快照读都生成快照** 那么low_limit_id就永远是当前系统下最大的事务ID。 所以就能保证只要其他事务commit了 其他事务不是活跃事务了 那么就只剩下了在up_limit_id和low_limit_id之间但是没在m_ids里面这两种情况。 也就一定能看到了。 所以这就是RC的形成原因。 这就是RR和RC的根本区别——————以上就是本节全部内容哦 如果对友友们有帮助的话可以关注博主 方便学习更多知识哦
延伸阅读

更多相关文章

2026/10/24 23:52:57

Qt Ribbon界面开发实战:基于QxRibbon仿WPS风格桌面应用

简介:本资源是一个基于Qt 5.13.2实现的Ribbon风格GUI界面库,专为希望快速构建WPS Office类现代化办公界面的C开发者设计,适用于桌面端跨平台应用开发场景,尤其适合具备Qt Widgets基础并希望进阶UI架构能力的中高级开发者。压缩包共…

2026/10/25 0:08:32

【MySQL】全面学习数据库查询技巧:查询指令深度学习指南

*前言:本节内容讲述基本查询, 基本查询要分为两篇文章进行讲解。 本篇文章主要讲解的是where子句、order by、limit查询。 如果想要学习对应知识的可以观看哦。> > ps:本篇内容友友们只要会创建表了就可以看起来了哦!!&…

2026/10/26 1:56:18

【MySQL】MySQL连接池原理与简易网站数据流动是如何进行

MySQL连接池原理与简易网站数据流动是如何进行* 1.MySQL连接池原理* 2.简易网站数据流动是如何进行> 点赞???收藏???关注??? > **你的支持是对我最大的鼓励,我们一起努力吧???**1.MySQL连接池原理------------目前我们对mysql有了一定的理解&…

2026/10/27 21:16:09

Clawdbot:模块化爬虫工具的核心架构与实战应用

1. Clawdbot 到底是什么? 第一次听说Clawdbot这个名字时,我也是一头雾水。直到上周在调试一个分布式爬虫项目时,偶然发现同事的代码里引用了这个库,才真正开始了解它。简单来说,Clawdbot是一个专门为数据采集场景设计的…

2026/10/27 21:16:09

多无人机协同路径规划:基于Dubins路径与PSO算法的实现

1. 项目概述:复杂威胁环境下的多无人机协同路径规划在无人机集群作业场景中,路径规划是最核心的技术挑战之一。当多架无人机需要在存在障碍物、禁飞区、雷达探测区等多种威胁的复杂环境中协同执行任务时,传统的单机路径规划方法往往难以满足需…

2026/10/27 21:16:09

AI音频技术解析:从生成模型到商业应用

1. 项目背景与核心定位"AI版Spotify"这个概念最近在海外科技圈引发了不小震动。作为连续创业者,周亚辉这次选择避开国内互联网巨头的战场,将目光投向了海外市场的AI音频赛道。这个决策背后反映的是当前中国科技创业者的典型困境——在国内市场…

2026/10/27 21:16:09

Neo4j图数据库在大数据可视化中的核心优势与应用

1. 为什么选择Neo4j处理大数据可视化?在数据爆炸的时代,传统关系型数据库处理海量关联数据时常常力不从心。我三年前接手一个电信运营商项目时就深有体会——当需要分析超过5000万用户之间的通话关系网络时,MySQL这类数据库的JOIN操作简直是一…

2026/10/27 21:16:09

Docker数据卷核心原理与生产环境实战指南

1. Docker数据卷的本质与核心价值 数据卷(Volume)是Docker容器化技术中最容易被低估却至关重要的功能组件。与传统的容器内文件系统不同,数据卷提供了独立于容器生命周期的持久化存储方案。当容器被删除时,其内部文件系统会随之销…

2026/10/27 21:11:09

VC6.0下最快的Delaunay TIN三角网生成算法源码解析

简介:这份资源面向计算机图形学、GIS 与测绘方向的开发者及学生,提供一套基于 VC6.0 实现的快速 TIN 三角网生成算法工程,可用于地形建模、点云网格化与 Delaunay 三角剖分等场景的学习与二次开发。压缩包共 88 个文件,约 769KB&a…

2026/10/27 14:24:03

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/27 9:34:54

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/27 0:59:21

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式19_“模式选错”的典型代价

“模式选错”的典型代价 摘要 在软件工程中,设计模式、架构模式、并发模式乃至团队协作模式的选择,往往在项目早期就决定了后续的开发效率和维护成本。本文通过多个真实场景,剖析“模式选错”带来的典型代价——包括返工成本、技术债务累积、…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式20_新手推荐路径

新手推荐路径 摘要 在 AI 辅助开发工具快速普及的今天,新手面对最多的困惑往往不是"工具够不够强",而是"我该从哪一步开始用"。本文提出一条经过实践验证的三阶段学习路径:先从 Ask(问答式交互)起…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑