【MySQL数据库 | 第二十五篇】深入探讨MVCC底层原理

前言: 

在当今互联网时代,数据库扮演着数据存储和管理的关键角色。对于大型Web应用程序和企业级系统而言,高效地处理并发访问和事务管理是至关重要的。多版本并发控制(MVCC)是一种数据库事务处理的技术,旨在提高并发性和数据一致性,而MySQL是其中一个广泛采用MVCC的数据库管理系统

在本文中,我们将深入探讨MVCC的概念、原理和实现方式,特别关注MySQL中MVCC的实现。我们将探讨MVCC是如何克服传统数据库锁定机制的局限性,从而实现更高的并发性和更好的数据一致性。通过深入了解MVCC,读者将能够更好地理解MySQL的工作原理,并能够优化数据库设计和性能调优。

目录

前言: 

当前读:

快照读:

MVCC:

实现原理:

RC隔离级别下:

RR隔离级别下:

总结: 


本片的数据库表的属性,如果没有特殊说明,那默认就是(innoDB+RR) 

 在介绍MVCC之前,我们要先介绍两个概念:

当前读:

读取的是当前记录的最新版本,读取的时候还需要保证其他并发事务不能修改当前记录,会对当前记录加锁。对于我们日常的select......lock in share modeselect......for updateupdateinsertdelete都是一种当前读。

快照读:

读取的是数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。常见隔离级别下的select:

  • RC:每一次select,都生成一个快照读。
  • RR:开启一个事务之后,只有第一个select语句才会生成一张快照,此后读的都是快照中的数据,直到事务提交。
  • Serializable:快照读退化为当前读。

我们用一个例子来看一下,以下为我们模拟的表数据(数据库默认使用InnoDB,隔离级别为RR):

我们同时开启两个MySQL客户端来对这张表进行操作:

 先尝试读取数据,这种能读取到表中最新数据的模式就叫做当前读。现在我们来看看什么是快照读

1.创建两个MySQL客户端,都开启事务,并且在第一个MySQL客户端中做一次SQL查询。

2.在第二个MySQL客户端中对id为1的用户姓名进行修改,并且提交当前事务。

3.重新在第一个MySQL客户端中查询。

我们会发现:第一个MySQL客户端中读取的数据竟然是老数据。这是为什么呢?

原因很简单:之前我们讲过MySQL的innoDB引擎在RR的隔离级别下,当我们开启事务的时候,只有第一次Select是当前读,读取完之后会生成一张快照,此后这个事务中后续的所有相同的select语句读的都是第一次Select所生成的快照。

当我们提交第一个MySQL客户端的时候之后,再尝试select * from emp ,会发生什么呢?

我们可以发现,此时就可以读取到正常的数据了。也就是说在InnoDB中select....... in share mode语句就是当前读。


MVCC:

        MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种用于数据库管理系统中实现并发控制的技术。它允许多个事务同时对数据库进行读写操作而不会导致数据不一致或丢失。

MVCC 的核心思想是在数据库中维护多个数据版本,并根据事务的隔离级别来决定哪个版本对特定事务是可见的。快照读就为MVCC提供了一个非阻塞读的功能,MVCC的具体实现还需要依赖数据库中的三个隐式字段undo log 日志readView

实现原理:

1.记录中的隐藏字段:当我们尝试创建一张表之后,InnoDB会自动为我们加上两个字段:

  • DB_TRX_ID:最近一次修改或删除记录的事务ID
  • DB_ROLL_PTR:回滚指针,指向记录的上一个版本
  • DB_ROW_ID:隐藏主键,如果表结构没有主键,将会生成该隐藏字段

2.undo log 日志:

  • Undo 日志记录了对数据的修改操作,包括插入、更新、删除等。
  • Undo 日志中记录了修改前的数据值,以及撤销操作所需的信息,以便在事务回滚或 MVCC 中使用。
  • 当事务提交的时候,相关的Undo log 日志就被标记为可回收状态,可以在之后的操作中被回收

如果是insert语句,那么Undo log日志只需要在回滚的时候需要,当事务提交之后,会被立即删除。

如果是update,delete的时候,产生的undo log日志不仅在回滚的时候需要,在产生快照读的时候也需要,因此其不会被立即删除。(undo log 中残留的旧版本数据可供其他并发事务进行快照读)

3.undo log 版本链:

(本图来自黑马程序员,偷懒了没画,如有侵权,请联系我立即删除)

 

 4.readview

readview是快照读SQL执行时候MVCC提取数据的依据,记录并且维护当前事务活跃的事务(未提交)的id。

ReadView包含了四个核心字段:

字段含义
m_min_trx_id最小活跃事务ID
max_try_id预分配事务ID,其实是当前最大事务ID+1(因为事务是自增的)
m_ids当前活跃的事务ID集合
creator_trx_idReadView创建者的事务ID

那么基于readView,其实就已经决定了哪些事务可以访问undo的哪些数据版本:

InnoDB不同的隔离级别,生成ReadView的实际不同:

  • READ COMMITTED : 在事务每一次执行快照读的时候生成ReadView。
  • REPEATABLE READ:仅在事务中第一次执行快照读的时候生成ReadView,后续一致复用该ReadView。 

我们来口述以下在这两种不同的隔离级别下,具体读取的是哪一个版本的快照:

RC隔离级别下:

其实就是去做比较,将undo log 中的DB_TRX_ID套入比较规则中,只要一个比较符合规则,那么就可以进行读取该版本的数据

经过一个一个的尝试,我们可以发现DB_TRX_ID=2的时候 ,符合比较规则2:trx_id<min_trx_id。

因此我们事务5中第一次查询id为30的记录的时候,实际上读的是DB_TRX_ID=2的快照读。

其实这四个比较看起来比较唬人,其实很好理解:RC是读已提交,也就是说我们的事务5在读取的时候,要么读取在自己之前已经提交了事务的版本数据要么读取自己修改的数据。那我们返回表中看:只有事务2在表5第一条语句之前提交了事务,因此我们事务5可以读事务2的数据版本。

因此我们可以看到RC可以防止脏读,因为它用的数据版本就是一个已经提交了事务的数据版本,自然不可能读到其他事务还没有提交的数据

RR隔离级别下:

RR隔离级别下,单个事务中一直复用的是该事务第一次查询版本快照。在当前案例中,事务5一直复用的就是自己第一次查询id等于30的数据记录。

因此我们可以看到RR可以防止重复读,这是因为事务一直使用的是自己第一次产生的readview,readview一样,那么匹配到的历史数据版本就一样,如果我们一直读取的都是一个历史版本数据,自然不可能出现两次读取结果不一致的情况了。

总结: 

        MVCC 是数据库系统中一种重要的并发控制机制,它通过在数据库中维护多个版本的数据来支持事务的并发执行,并提供了一致性读取和隔离性的保证。在 MVCC 中,每个事务都可以看到一个独立的数据版本,这使得读操作不会被写操作所阻塞,从而提高了数据库的并发性能。

MVCC 的实现主要依赖于两个关键组件:Undo 日志和版本链。Undo 日志记录了事务执行过程中对数据所做的修改操作,用于在事务回滚或撤销时恢复数据到之前的状态。而版本链则是指数据库中维护的多个数据版本之间的关系,包括当前版本、已提交版本和未提交版本等。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

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

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

相关文章

【复现】用友NC-Cloud文件上传漏洞_70

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 用友NC Cloud大型企业数字化平台&#xff0c;深度应用新一代数字智能技术&#xff0c;完全基于云原生架构&#xff0c;打造开放、…

【Axure高保真原型】马赛克效果

今天和大家分享动态画出马赛克效果的原型模板&#xff0c;鼠标按着左键拖动&#xff0c;可以在对应位置拖出马赛克&#xff0c;具体效果可以观看下方视频或者打开预览地址体验。 【原型效果】 【Axure高保真原型】马赛克效果 【原型预览含下载地址】 https://cspfgk.axshare.…

一例简单的文件夹病毒的分析

概述 这是一个典型的文件夹病毒&#xff0c;使用xp时代的文件夹图标&#xff0c;通过可移动存储介质传播&#xff0c;会向http://fionades.com/ABIUS/setup.exe下载恶意载荷执行。 其病毒母体只是一个加载器&#xff0c;会在内存是解密加载一个反射型的dll&#xff0c;主要的…

<网络> 网络Socket编程基于TCP协议模拟简易网络通信

目录​​​​​​​ 前言&#xff1a; 一、字符串回响 &#xff08;一&#xff09;程序结构 &#xff08;二&#xff09;初始化服务器 &#xff08;三&#xff09;启动服务器 1. 处理连接请求 2. 业务处理 3. 回调函数 &#xff08;四&#xff09;填充server源文件 &…

春秋云境28512

题目说该CMS的/single.php路径下&#xff0c;id参数存在一个SQL注入漏洞。访问看一下随便点一个图片。 发现了注入点?id 那么开始查看闭合符一个 就报错了 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for th…

Unity多线程简单示例

using UnityEngine; using System.Threading;public class texxxst : MonoBehaviour {Thread thread;void Start(){// 创建一个新的线程&#xff0c;并传入要执行的方法thread new Thread(new ThreadStart(DoWork));// 启动线程thread.Start();}void DoWork(){for (int i 0; …

【机器学习】机器学习创建算法第5篇:线性回归,学习目标【附代码文档】

机器学习&#xff08;算法篇&#xff09;完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;机器学习算法课程定位、目标&#xff0c;K-近邻算法定位,目标,学习目标,1 什么是K-近邻算法,1 Scikit-learn工具介绍,2 K-近邻算法API。K-近邻算法&#xff0c;1.4 …

Day30 回溯 LeedCode 332.重新安排行程 51. N皇后 37. 解数独 蓝桥杯 与或异或

332. 重新安排行程 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&#xff0c;所以该行程必须从 JFK…

2、Qt UI控件 -- qucsdk项目使用

前言&#xff1a;上一篇文章讲了qucsdk的环境部署&#xff0c;可以在QDesigner和Qt Creator中看到qucsdk控件&#xff0c;这一篇来讲下在项目中使用qucsdk库中的控件。 一、准备材料 要想使用第三方库&#xff0c;需要三个先决条件&#xff0c; 1、控件的头文件 2、动/静态链…

LeetCode 239. 滑动窗口最大值

滑动窗口最大值 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1&#xff1a; 输入&#xff1a;nums [1,3,-1,-3,…

数据生成 | Matlab实现基于DE差分进化算法的数据生成

数据生成 | Matlab实现基于DE差分进化算法的数据生成 目录 数据生成 | Matlab实现基于DE差分进化算法的数据生成生成效果基本描述模型描述程序设计参考资料 生成效果 基本描述 1.Matlab实现基于DE差分进化算法的数据生成&#xff0c;运行环境Matlab2021b及以上&#xff1b; 2.计…

FreeRTOS任务切换学习

FreeRTOS任务切换学习 所谓任务切换&#xff0c;就是CPU寄存器的切换。假设当由任务A切换到任务B时&#xff0c;主要分为两步&#xff1a; 1&#xff1a;需暂停任务A的执行&#xff0c;并将此时任务A的寄存器保存到任务堆栈&#xff0c;这个过程叫做保存现场&#xff1b; 2&am…

设计模式-接口隔离原则

基本介绍 客户端不应该依赖它不需要的接口&#xff0c;即一个类对另一个类的依赖应该建立在最小的接口上先看一张图: 类A通过接口Interface1 依赖类B&#xff0c;类C通过接口Interface1 依赖类D&#xff0c;如果接口Interface1对于类A和类C来说不是最小接口&#xff0c;那么类…

Unity之PUN实现多人联机射击游戏的优化(Section 2)

目录 &#x1f3ae;一、准备工作 &#x1f3ae;二、实现手雷投掷动作 &#x1f3ae;三、手雷投掷同步 &#x1f4a4;3.1 photonView.RPC &#x1f3ae;四、同步手雷伤害 这几周都给我布置任务了&#xff0c;最近可忙。现在终于有机会更新了&#xff0c;也谢谢大家的阅读&a…

爬虫 新闻网站 以湖南法治报为例(含详细注释) V1.0

目标网站&#xff1a;湖南法治报 爬取目的&#xff1a;为了获取某一地区更全面的在湖南法治报已发布的宣传新闻稿&#xff0c;同时也让自己的工作更便捷 环境&#xff1a;Pycharm2021&#xff0c;Python3.10&#xff0c; 安装的包&#xff1a;requests&#xff0c;csv&#xff…

dyld: Library not loaded: @rpath/SDK.framework/SDK错误问题

关于导入三方SDK.framework之后&#xff0c;启动崩溃之后如下报错的解决方式: 截屏2020-10-14 上午9.55.09.png 在正常导入framework之后&#xff0c;做如图示操作&#xff0c; image.png 以上步骤之后&#xff0c;重新启动运行xcode&#xff0c;即可成功运行。

人工智能、深度伪造和数字身份:企业网络安全的新前沿

深度伪造&#xff08;Deepfakes&#xff09;的出现打响了网络安全军备竞赛的发令枪。对其影响的偏执已经波及到一系列领域&#xff0c;包括政治错误信息、假新闻和社交媒体操纵。 深度伪造将加剧公共领域对信任和沟通的本已严峻的压力。这将理所当然地引起监管机构和政策制定者…

嵌入式学习第三十二天!(队列)

1. 队列的定义&#xff1a; 队列&#xff1a;是只允许一端进行数据插入&#xff0c;而另一端进行数据删除的线性表。&#xff08;先进先出FIFO&#xff09;&#xff0c;如下图所示。 队列的应用&#xff1a;缓冲区&#xff0c;即解决高速设备和低速设备数据交互的时候&#xff…

蓝桥2021A组C题

货物摆放 问题描述格式输入格式输出评测用例规模与约定解析参考程序难度等级 问题描述 格式输入 无 格式输出 输出答案 评测用例规模与约定 无 解析 数字给的相当大所以我们不能直接给他暴力了&#xff0c;不然等很久都跑不出来。由题目我们可以得到让nLxWxH&#xff0c;所…

day77 JSPServlet

知识点&#xff1a; 1Web工程 2JSP是什么&#xff1f;JSP页面包含哪些内容&#xff1f;JSP页面执行原理 3JSP九大内置对象&#xff0c;及四个作用域 4什么是SERVLET&#xff1f;及servlet相关API 5MVC模型 6EL表达式及JSTL标签库的使用 7在JSP页面实现分页和多条件查询 …