MySQL多版本并发控制MVCC实现原理
MVCC
MVCC 是多版本并发控制方法,用来解决读和写之间的冲突,比如脏读、不可重复读问题,MVCC主要针对读操作做限制,保证每次读取到的数据都是本次读取之前的已经提交事务所修改的。
概述
当一个事务要对数据库中的数据进行select查找时,MVCC 会为该事务创建一个read view数据快照,查询语句会把在read view产生之前没提交的修改以及在read view产生之后才提交的事务对应的修改屏蔽掉,最终只能读取到这个read view产生之前其它事务所提交的更改。换句话说,读操作读取的是旧版本数据(也可能是最新的),而写操作是针对最新的版本记录,所以能解决读-写冲突问题。
具体实现
它基于数据行的隐藏字段、undo log版本链、read view实现:
数据隐藏字段:最后修改事务id、回滚记录指针

undo log 版本链:用于记录某行数据的多个版本的数据,通过一个回滚指针字段链接起来

read view : 每个事务的读取时会产生一个read view,记录了一些列的事务id,具体有如下四个字段:
- creator_trx_id,创建当前Read View的事务ID。
- trx_ids,表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。
- min_limit_trx_id,活跃的事务中最小的事务id。
- max_trx_id,表示生成ReadView时系统中应该分配给下一个事务的id值。low_limit_id是系统最大的事务id值,这里要注意是系统中的所有事务id,不仅包含正在活跃的事务id、还包含之前已提交的事务id。
注意:
- 只有在对表中的记录做改动时(执行INSERT、DELETE、UPDATE这些语句时)才会为事务分配事务id,否则在一个只读事务中的事务id值都默认为0。
- low_limit_id并不是活跃事务列表trx_ids中的最大值,而是所有事务id中最大的+1,这里的所有事务包括活跃的、已提交的。比如,现在有id为1,2,3这三个事务,之后id为3的事务提交了。那么一个新的读事务在生成ReadView时,trx_ids就包括1和2,up_limit_id的值就是1,low_limit_id的值就是4。
MVCC工作流程
- 某个事务执行select查找时,首先根据数据行的某个字段获取事务自己的版本号,也就是事务ID;
- 然后创建ReadView;
- 查询得到最新数据,然后与ReadView中的事务版本号按照一定规则进行比较;
- 如果不符合ReadView规则,就需要从Undo Log 中获取历史快照;
- 一直往前查找,直到返回符合规则的数据。
read view是怎么去找到当前read view创建之前已经提交修改的最新数据的,具体规则是什么?
先根据数据行记录的回滚指针,在undo日志中找到最新一条记录,找到其对应的事务id,然后做四轮对比:
- 对比最新记录的事务id和当前read view的事务id,如果相同,则说明最新的数据就是当前事务修改的,可以直接读。(等于当前id,代表是自己改的,则可读)
- 对比最新记录的事务id和当前read view的记录的活跃事务id最小值,看看是不是当前记录是不是read view创建之前就已经提交完的,如果是,则可以直接读。(小于最小活跃事务id,代表之前提交的修改,则可读)
- 对比最新记录的事务id和当前read view的记录的最大事务id,看看当前记录是不是read view创建之后才有的,如果是就不读。(大于最大事务id,代表后面才提交的修改,不可读)
- 对比最新记录的事务id是不是存在于当前活跃事务id列表当中,如果存在,则说明是未提交的数据,不能读取;如果不存在,则可读。(在活跃事务列表里,代表未提交的修改,可读)
这四轮对比完之后,如果都显示不能读,则找到undo日志的下一跳数据,继续四轮对比。知道找到某条可读的记录。
假设事务5创建read view时,系统中有8个事务,对应查找情况如下:

疑问:其实整个流程就是把那些活跃事务(未提交)造成的修改排除掉,然后再判断下当前事务是创建read view之前提交的还是创建read view之后提交的,那为什么要在最后一步才去判断事务id是否在活跃id列表中?
自我理解:因为判断某个id是否在活跃事务id列表里,需要一次遍历操作,放在第一步去做的话每次都要遍历,速度很慢;其实可以先把其它情况处理掉(不需要遍历),当别的情况都不满足时,最后再考虑是否在活跃id列表中,以此提高查找效率。
事务隔离级别与MVCC
四个事务隔离级别与MVCC的关系?
首先,最低的读未提交和串行化没有用到MVCC机制,而读已提交和可重复度用到了MVCC去解决读写冲突中的脏读取和不可重复读的问题。
读已提交隔离级别中,MVCC怎么解决脏读的?
同一个事务中每次读取时创建一个read view,根据read view中记录的事务id去undo log中把其它未提交事务的记录个过滤掉,只会读取已提交事务所造成的修改。
问题:因为每次查询都会创建一个read view,所以两次查询之间,如果其它事务对数据进行修改,这时对第二次查询产生的read view的视角下,刚刚的修改是可见的,所以这就有了不可重复读的问题。

可重复读隔离级别中,MVCC怎么解决不可重复读?保证可重复读?
对于同一个事务中对同一条数据的多次读取,复用之前的read view,也就是只有在首次读取数据时才会产生read view,这就避免了出现在一个事务中的多次读取结果不一样的情况。

总结MVCC机制
MVCC 是多版本并发控制方法,用来解决读和写之间的冲突,比如脏读、不可重复读问题,MVCC主要针对读操作做限制,保证每次读取到的数据都是本次读取之前的已经提交事务所修改的。
它具体实现依赖于数据行隐藏字段、undo log版本链和read view。
具体过程:在某个事务执行读操作时,可以通过数据行的隐藏列去找到undo日志中的历史版本记录,每个历史版本记录里面都记录了事务id,然后会读操作会创建一个read view视图,里面包含了一些事务id的数据,然后通过对比read view里面的事务id数据和undo版本链中的事务id数据,就可以找到read view创建之前所提交的数据。
追问:read view具体记录了哪些数据,具体怎么去和undo log中记录的id对比,最后找到想要的数据的?
read view视图里面记录了当前事务id、当前未提交事务(活跃事务)id列表、当前未提交事务id列表的最小值、当前最大事务id。先找到undo log第一条数据,对比事务id和read view当前事务id是否一样。。,对比事务id是不是小于最小活跃事务id。。。,然后对比事务id是不是大于最大事务id。。。,最后判断事务id是不是在活跃事务id列表里面。。
相关文章:
MySQL多版本并发控制MVCC实现原理
MVCC MVCC 是多版本并发控制方法,用来解决读和写之间的冲突,比如脏读、不可重复读问题,MVCC主要针对读操作做限制,保证每次读取到的数据都是本次读取之前的已经提交事务所修改的。 概述 当一个事务要对数据库中的数据进行selec…...
【并查集】[ABC372E] K-th Largest Connected Components 题解
题意 前置阅读:并查集算法介绍 洛谷链接 Atcoder 链接 给定 n ( 1 ≤ n ≤ 2 1 0 5 ) n(1 \leq n \leq 2\times 10^5) n(1≤n≤2105) 个点,初始没有边,您要进行以下操作: 1 a b,表示连接一条 ( a , b ) (a,b) …...
HarmonyOS面试题(持续更新中)
1、用过线程通信吗,线程是怎么进行通信的? emitter 和 eventHub 相同: 都是基于事件总线的 区别是: ① eventHub当前线程内通信 ② emitter是同一进程不同线程或者同一进程和同一线程也可以通信 2、页面和组件的生命周期 …...
QT中QWidget和QObject的区别与联系是什么
在Qt框架中,QWidget和QObject是两个核心类,它们各自扮演着不同的角色,但又紧密相连。以下是关于它们区别与联系的详细解释: 区别 基类和功能定位: QObject是Qt中所有类的基类,包括几乎所有的Qt对象。它提供…...
解决macOS安装redis以后不支持远程链接的问题
参考文档:https://blog.csdn.net/qq_37703224/article/details/142542179?spm1001.2014.3001.5501 安装的时候有个提示, 使用指定配置启动: /opt/homebrew/opt/redis/bin/redis-server /opt/homebrew/etc/redis.conf那么我们可以尝试修改这个配置文件: code /opt/homebrew/…...
2024年研究生数学建模“华为杯”E题——肘部法则、k-means聚类、目标检测(python)、ARIMA、逻辑回归、混淆矩阵(附:目标检测代码)
文章目录 一、情况介绍二、思路情况二、代码展示三、感受 一、情况介绍 前几天也是参加了研究生数学建模竞赛(也就是华为杯),也是和本校的两个数学学院的朋友在网上组的队伍。昨天(9.25)通宵干完论文(一条…...
绝了,自从用了它,我每天能多摸鱼2小时!
大家好,我是可乐。 俗话说的好:“摸鱼一时爽,一直摸鱼一直爽”。 作为一个程序员,是否有过调试代码熬到深夜?是否有过找不到解决方案而挠秃头顶? 但现在你即将要解放了,用了这款工具——秘塔…...
C语言指针系列1——初识指针
祛魅:其实指针这块儿并不难,有人说难只是因为基础到进阶没有处理好,大家要好好跟着一步一步学习,今天我们先来认识一下指针 指针定义:指针就是内存地址,指针变量是用来存放内存地址的变量,在同一…...
传神论文中心|第26期人工智能领域论文推荐
在人工智能领域的快速发展中,我们不断看到令人振奋的技术进步和创新。近期,开放传神(OpenCSG)传神社区发现了一些值得关注的成就。传神社区本周也为对AI和大模型感兴趣的读者们提供了一些值得一读的研究工作的简要概述以及它们各自…...
NLP基础1
NLP基础1 深度学习中的NLP的特征输入 1.稠密编码(特征嵌入) 稠密编码(Dense Encoding):指将离散或者高纬的稀疏数据转化为低纬度的连续、密集向量表示 特征嵌入(Feature Embedding) 也称…...
001.docker30分钟速通版
docker简介 docker就是一个用于构建(build),运行(run),传送(share)应用程序的平台做一个不恰当的类比,就是外卖平台,如果你自己做华莱士不一定好吃࿰…...
Kafka 在 Linux 下的集群配置和安装
Kafka 在 Linux 下的集群配置和安装 Apache Kafka 是一个流行的分布式流处理平台,广泛用于实时数据管道和流处理应用。本文将详细讲解如何在 Linux 环境中配置和安装 Kafka 集群,并包括通过 Docker 安装和配置 Kafka 的步骤。每个步骤都将提供详细的解释…...
Python--操作列表
1.for循环 1.1 for循环的基本语法 for variable in iterable: # 执行循环体 # 这里可以是任何有效的Python代码块这里的variable是一个变量名,用于在每次循环迭代时临时存储iterable中的下一个元素。 iterable是一个可迭代对象,比如列表(…...
JMeter(需要补充请在留言区发给我,谢谢)
一、学习工具 1、CinfigElement(HTTP Request Defaults、HTTP Header Manager、HTTP Authorization、CSV Data Set Config、User Defined Variables、JDBC Connection Configuration、HTTP Cookie Manager、Random Variable) 二、协议 1、HTTP协议(消息体数据&am…...
线程池的执行流程和配置参数总结
一、线程池的执行流程总结 提交线程任务;如果线程池中存在空闲线程,则分配一个空闲线程给任务,执行线程任务;线程池中不存在空闲线程,则线程池会判断当前线程数是否超过核心线程数(corePoolSize)…...
node-red-L3-重启指定端口的 node-red
重启指定端口 目的步骤查找正在运行的Node.js服务的进程ID(PID):停止Node.js服务:启动Node.js服务: 目的 重启指定端口的 node-red 步骤 在Linux系统中,如果你想要重启一个正在运行的Node.js服务&#x…...
(done) 使用泰勒展开证明欧拉公式
问问神奇的 GPT,how to prove euler formula? 一个答案如下:...
红队apt--邮件钓鱼
前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 免责声明: 本文仅供了解攻击方手法使用,切勿用于非授权情节 初步了解邮件基础 用途方面 这个我们应该比较熟悉,最常用于验证码接收,也有一些厂商会用这个来打广告,…...
十七,Spring Boot 整合 MyBatis 的详细步骤(两种方式)
十七,Spring Boot 整合 MyBatis 的详细步骤(两种方式) 文章目录 十七,Spring Boot 整合 MyBatis 的详细步骤(两种方式)1. Spring Boot 配置 MyBatis 的详细步骤2. 最后: MyBatis 的官方文档:https://mybatis.p2hp.com/ 关于 MyBa…...
DNS协议解析
DNS协议解析 什么是DNS协议 IP地址:一长串唯一标识网络上的计算机的数字 域名:一串由点分割的字符串名字 网址包含了域名 DNS:域名解析协议 IP>域名 --反向解析 域名>IP --正向解析 域名 由ICANN管理,有级别…...
RRFLibraries:Duet 3D打印机固件的硬实时C++驱动库
1. RRFLibraries 项目概述RRFLibraries 是 RepRapFirmware 生态系统中高度工程化的底层软件基础设施,其定位并非通用型嵌入式库,而是专为 3D 打印固件——特别是 Duet 系列控制器(Duet 2 WiFi、Duet 3 Mainboard、Duet 3 Mini)——…...
数值分析实战指南:北航研究生大作业解析与代码实现
1. 数值分析大作业的核心价值 第一次接触北航研究生数值分析大作业时,我和大多数同学一样感到无从下手。直到在实验室熬了三个通宵后,我才真正明白这份作业的独特价值——它完美架起了理论与实践的桥梁。这份大作业最精妙之处在于,它不仅仅是…...
轻量级嵌入式按键驱动库:BartOS-button设计与多平台实践
1. BartOS-button 库概述BartOS-button 是为 BartOS 嵌入式实时操作系统项目配套开发的轻量级按键驱动库,专为资源受限的 IoT 终端设备设计。该库不依赖特定硬件抽象层(HAL),采用纯 C 实现,支持裸机(Bare-m…...
从HC-SR04到智能报警:手把手教你用51单片机做个超声波倒车雷达原型
从HC-SR04到智能报警:手把手教你用51单片机做个超声波倒车雷达原型 在汽车电子和智能硬件领域,倒车雷达作为基础安全配置已经普及多年。但对于电子爱好者和嵌入式开发者来说,用最基础的51单片机搭配HC-SR04超声波模块实现一个具备三级报警功能…...
深度解析ThreeFingerDragOnWindows:Windows触控板三指拖动技术实现
深度解析ThreeFingerDragOnWindows:Windows触控板三指拖动技术实现 【免费下载链接】ThreeFingersDragOnWindows Enables macOS-style three-finger dragging functionality on Windows Precision touchpads. 项目地址: https://gitcode.com/gh_mirrors/th/ThreeF…...
告别手动画图?聊聊Autoware高精地图那些事:开源工具、格式转换与未来展望
自动驾驶高精地图技术全景:从Autoware工具链到行业实践 当我们在谈论自动驾驶时,"高精地图"始终是绕不开的核心技术支柱。与普通导航地图不同,高精地图需要厘米级精度、丰富的语义信息以及实时更新能力。作为自动驾驶开源生态中的重…...
终极LoRaWAN服务器搭建指南:如何快速构建你的私有物联网网络
终极LoRaWAN服务器搭建指南:如何快速构建你的私有物联网网络 【免费下载链接】lorawan-server Compact server for private LoRaWAN networks 项目地址: https://gitcode.com/gh_mirrors/lo/lorawan-server 你是否想拥有一个完全可控的LoRaWAN物联网平台&…...
解决RK3588安装OpenCV时libjasper-dev缺失问题:Ubuntu20.04特殊源配置教程
RK3588平台OpenCV安装困境:深度解析libjasper-dev缺失问题与多维度解决方案 在RK3588平台上部署计算机视觉应用时,OpenCV作为核心依赖库的安装过程往往成为开发者的第一个"拦路虎"。特别是在Ubuntu 20.04环境下,当执行标准的sudo a…...
128K上下文开源代码模型:DeepSeek-Coder-V2赋能开发者的技术解析
128K上下文开源代码模型:DeepSeek-Coder-V2赋能开发者的技术解析 【免费下载链接】DeepSeek-Coder-V2 项目地址: https://gitcode.com/GitHub_Trending/de/DeepSeek-Coder-V2 在软件开发效率日益成为竞争力核心指标的今天,开发者面临着代码生成质…...
Arduino库管理终极指南:在VS Code中如何优雅添加自定义头文件(避坑版)
Arduino库管理终极指南:在VS Code中优雅添加自定义头文件 第一次在VS Code里看到"fatal error: my_library.h: No such file or directory"的红色报错时,我盯着屏幕发了五分钟呆。作为从Arduino IDE转战VS Code的老玩家,本以为能无…...
