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,具体有如下四个字段:

  1. creator_trx_id,创建当前Read View的事务ID
  2. trx_ids,表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。
  3. min_limit_trx_id,活跃的事务中最小的事务id
  4. max_trx_id,表示生成ReadView时系统中应该分配给下一个事务的id值。low_limit_id是系统最大的事务id值,这里要注意是系统中的所有事务id,不仅包含正在活跃的事务id、还包含之前已提交的事务id。

注意:

  1. 只有在对表中的记录做改动时(执行INSERT、DELETE、UPDATE这些语句时)才会为事务分配事务id,否则在一个只读事务中的事务id值都默认为0。
  2. 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工作流程

  1. 某个事务执行select查找时,首先根据数据行的某个字段获取事务自己的版本号,也就是事务ID;
  2. 然后创建ReadView;
  3. 查询得到最新数据,然后与ReadView中的事务版本号按照一定规则进行比较;
  4. 如果不符合ReadView规则,就需要从Undo Log 中获取历史快照;
  5. 一直往前查找,直到返回符合规则的数据。

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列表里面。。

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

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

相关文章

十七,Spring Boot 整合 MyBatis 的详细步骤(两种方式)

十七,Spring Boot 整合 MyBatis 的详细步骤(两种方式) 文章目录 十七,Spring Boot 整合 MyBatis 的详细步骤(两种方式)1. Spring Boot 配置 MyBatis 的详细步骤2. 最后: MyBatis 的官方文档:https://mybatis.p2hp.com/ 关于 MyBa…

828华为云征文|使用Flexus X实例安装宝塔面板教学

目录 一、Flexus X实例简介 1.1 概述 1.2 产品规格 二、切换操作系统 2.1 Huawei Cloud EulerOS 2.0 标准版 2.2 切换镜像 三、部署宝塔面板 3.1 安装宝塔面板 3.2 放通安全组规则 3.3 登录宝塔面板 四、使用感受 4.1 柔性算力随心配 4.2 一直加速一直快 4.3 越用…

【小程序】微信小程序课程 -2 快速上手

目录 1、快速上手基本概念 1.1 小程序常用组件 1.2 tabbar配置 1.3 尺寸单位 1.4 样式 1.4.1 全局样式 app.wxss 1.4.2 局部样式 xx.wxss 2、首页案例 2.1 button组件使用 2.2 swiper swiper-item 2.3 tips效果 2.4 引入矢量图 2.5 flex(布局&#…

Java中List、ArrayList与顺序表

List、ArrayList与顺序表 List什么是List常用方法介绍List的使用 ArrayList与顺序表线性表顺序表接口的实现 ArrayList简介ArrayList的使用ArrayList的构造ArrayList的常见操作ArrayList的遍历ArrayList的扩容机制 ArrayList的具体使用杨辉三角简单的洗牌算法 ArrayList的问题及…

2024.9.26 作业 +思维导图

一、作业 1、什么是虚函数?什么是纯虚函数 虚函数:函数前加关键字virtual,就定义为虚函数,虚函数能够被子类中相同函数名的函数重写 纯虚函数:把虚函数的函数体去掉然后加0;就能定义出一个纯虚函数。 2、基…

前台项目启动/打包报错 Error: error:0308010C:digital envelope routines::unsupported

在package.json中修改启动/打包语句 如图,我这里是打包时候报错,就在build里前面加上 set NODE_OPTIONS--openssl-legacy-provider && 再次打包,成功。

刷题计划 day10 栈与队列上【用栈实现队列】【用队列实现栈】【有效的括号】【删除字符串中的所有相邻重复项】

⚡刷题计划day10栈与队列继续,可以点个免费的赞哦~ 往期可看专栏,关注不迷路, 您的支持是我的最大动力🌹~ 目录 ⚡刷题计划day10继续,可以点个免费的赞哦~ 往期可看专栏,关注不迷路, 您的…

Vue引入js脚本问题记录(附解决办法)

目录 一、需求 二、import引入问题记录 三、解决方式 一、需求 我想在我的Vue项目中引入jquery.js和bootstrap.js这种脚本文件,但发现不能单纯的import引入,问题如下。 二、import引入问题记录 我直接这么引入,发现控制台报错TypeError: …

使用kaggle命令下载数据集和模型

点击用户头像,点击Settings: 找到API,点击create new token,将自动下载kaggle.json: 在用户目录下创建.kaggle文件夹,并将下载的kaggle.json文件移动到该文件夹: cd ~ mv Downloads/kaggle.j…

postman控制变量和常用方法

1、添加环境: 2、环境添加变量: 3、配置不同的环境:local、dev、sit、uat、pro 4、 接口调用 5、清除cookie方法: 6、下载文件方法:

数据结构升华部分:排序与字符串匹配算法应用

数据结构入门学习(全是干货)——综合应用 习题选讲 - 排序与字符串匹配算法 习题选讲 - Insert or Merge 习题-IOM.1 插入排序的判断 题意理解 如何区分简单插入和非递归的归并排序 插入排序:前面有序,后面没有变化。归并排…

react hooks--useCallback

概述 useCallback缓存的是一个函数,主要用于性能优化!!! 基本用法 如何进行性能的优化呢? useCallback会返回一个函数的 memoized(记忆的) 值;在依赖不变的情况下,多次定义的时候,返回的值是…

【计算机组成原理】实验一:运算器输入锁存器数据写实验

目录 实验要求 实验目的 主要集成电路芯片及其逻辑功能 实验原理 实验内容及步骤 实验内容 思考题 实验要求 利用CP226实验箱上的K16~K23二进制拨动开关作为DBUS数据输入端,其它开关作为控制信号的输入端,将通过K16~K23设定…

Linux:终端(terminal)与终端管理器(agetty)

终端的设备文件 打开/dev目录可以发现其中有许多字符设备文件,例如对于我的RedHat操作系统,拥有tty0到tty59,它们是操作系统提供的终端设备。对于tty1-tty12使用ctrlaltF*可以进行快捷切换,下面的命令可以进行通用切换。 sudo ch…

【Linux】项目自动化构建工具-make/Makefile 详解

🔥 个人主页:大耳朵土土垚 🔥 所属专栏:Linux系统编程 这里将会不定期更新有关Linux的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉 文章目…

Studying-图论包含的算法总结

目录 1.DFS(深度优先搜索) 代码框架: 2. BFS(广度优先搜索) 代码框架: 3. 并查集 4.最小生成树之Prim 5.最小生成树之Kruskal 6.拓扑排序 7. 最短路径之-dijkstra(朴素版&#xff…

[附源码]在线音乐系统+SpringBoot+Vue前后端分离

今天带来一款优秀的项目:在线音乐系统源码 。 系统采用的流行的前后端分离结构,内含功能包括 "管理后台",“用户端”,“评论系统”,“歌手,歌曲管理”,“用户系统”,"统计"…

c++继承详解

从这篇文章开始,我们正式进入c进阶篇章 继承的概念及定义 概念 继承(inheritance)机制是⾯向对象程序设计使代码可以复⽤的最重要的⼿段,它允许我们在保持原有 类特性的基础上进⾏扩展 通俗来讲就是:父亲的遗产传给自己的子女,…

Autosar学习----AUTOSAR_SWS_BSWGeneral(七)

💥💥🔍 🔍 欢迎来到本博客❤️❤️💥💥 🐡优势:❤️博客内容尽量做到通俗易懂,逻辑清晰。 ⛳️座右铭:恒心,耐心,静心。 ⛳️ 欢迎一起…

力扣958:判断二叉树是否为完全二叉树

给你一棵二叉树的根节点 root ,请你判断这棵树是否是一棵 完全二叉树 。 在一棵 完全二叉树 中,除了最后一层外,所有层都被完全填满,并且最后一层中的所有节点都尽可能靠左。最后一层(第 h 层)中可以包含 …