MySQL:简述多版本并发控制MVCC

一、MVCC的概念

1、MVCC

数据库并发场景有三种,分别为:
(1)读读:不存在任何问题,也不需要并发控制。
(2)读写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读、幻读、不可重复读。
(3)写写:有线程安全问题,可能存在更新丢失问题。

MVCC,全称Multi-Version Concurrency Control,即多版本并发控制。是一种用来解决读写冲突的无锁并发控制,也就是为事务分配单项增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照,所以MVCC可以为数据库解决以下问题:
(1)在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能;
(2)解决脏读、幻读、不可重复读等事务隔离问题,但是不能解决更新丢失问题。

2、当前读

像共享锁、排它锁、update、insert、delete这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

-- 共享锁
select lock in share mode();
-- 排他锁
select ... for update;

3、快照读

像不加锁的select操作就是快照读,即不加锁的非阻塞读。快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读。

快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。

二、MVCC的实现原理

MVCC模块在MySQL中的具体实现是由三个隐式字段、Undo日志、ReadView三个组件来实现的。

MVCC 的实现方式:本质上,MVCC 就是用 UndoLog 链表实现。事务以排它锁的方式修改原始数据,把修改前的数据存放于 UndoLog,通过回滚指针与数据关联,如果修改成功,什么都不做,如果修改失败,则恢复 UndoLog中的数据。

1、隐式字段

InnoDB 每个聚簇索引都有 4 个隐藏字段,分别是主键(ROW_JD),最近更改的事务ID(TRX_ID),UndoLog 的指针(隔离核心),索引删除标记(当删除时,不会立即删除,而是打标记,然后异步删除)。本质上,MVCC 就是用 UndoLog 链表实现。
(1)DB_ROW_JD:6字节,隐藏的主键,如果数据表没有主键,那么innodb会自动生成一个6字节的row_id。
(2)DB_TRX_ID:6字节,最近修改事务id,记录创建这条记录或者最后一次修改该记录的事务id,是MVCC的核心。
(3)DB_ROLL_PTR:7字节,回滚指针,指向这条记录的上一个版本,用于配合UndoLog,指向上一个旧版本。
在这里插入图片描述

2、UndoLog

UndoLog被称之为回滚日志,表示在进行insert,delete,update操作的时候产生的方便回滚的日志。
(1)当进行insert操作的时候,产生的UndoLog只在事务回滚的时候需要,并且在事务提交之后可以被立刻丢弃。
(2)当进行update和delete操作的时候,产生的UndoLog不仅仅在事务回滚的时候需要,在快照读的时候也需要,所以不能随便删除,只有在快照读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除。

当数据发生更新和删除操作的时候都只是设置一下老记录的deleted_bit,并不是真正的将过时的记录删除,因为为了节省磁盘空间,innodb有专门的purge线程来清除deleted_bit为true的记录,如果某个记录的deleted_id为true,并且DB_TRX_ID相对于purge线程的ReadView可见,那么这条记录一定是可以被清除的。

下面我们来看一下UndoLog生成的记录链
1、假设有一个事务编号为1的事务向表中插入一条记录,那么此时行数据的状态为:
在这里插入图片描述
2、假设有第二个事务编号为2对该记录的name做出修改,改为lisi。
(1)在事务2修改该行记录数据时,数据库会对该行加排他锁,然后把该行数据拷贝到undolog中,作为旧记录,即在undolog中有当前行的拷贝副本。
(2)拷贝完毕后,修改该行name为lisi,并且修改隐藏字段的事务id为当前事务2的id,回滚指针指向拷贝到undolog的副本记录中。
(3)事务提交后,释放锁。
在这里插入图片描述
3、假设有第三个事务编号为3对该记录的age做了修改,改为32。
(1)在事务3修改该行数据的时,数据库会对该行加排他锁。然后把该行数据拷贝到undolog中,作为旧纪录,发现该行记录已经有undolog了,那么最新的旧数据作为链表的表头,插在该行记录的undolog最前面。
(2)拷贝完毕后,修改该行age为32岁,并且修改隐藏字段的事务id为当前事务3的id,回滚指针指向刚刚拷贝的undolog的副本记录。
(3)事务提交,释放锁。
在这里插入图片描述
从上述的一系列图中,大家可以发现,不同事务或者相同事务的对同一记录的修改,会导致该记录的undolog生成一条记录版本线性表,即链表,undolog的链首就是最新的旧记录,链尾就是最早的旧记录。

3、ReadView

Read View是事务进行快照读操作的时候生产的读视图,在该事务执行快照读的那一刻,会生成一个数据系统当前的快照,记录并维护系统当前活跃事务的id,事务的id值是递增的。

其实Read View的最大作用是用来做可见性判断的,也就是说当某个事务在执行快照读的时候,对该记录创建一个Read View的视图,把它当作条件去判断当前事务能够看到哪个版本的数据,有可能读取到的是最新的数据,也有可能读取的是当前行记录的undolog中某个版本的数据。

Read View遵循的可见性算法主要是将要被修改的数据的最新记录中的DB_TRX_ID(当前事务id)取出来,与系统当前其他活跃事务的id去对比,如果DB_TRX_ID跟Read View的属性做了比较,不符合可见性,那么就通过DB_ROLL_PTR回滚指针去取出undolog中的DB_TRX_ID做比较,即遍历链表中的DB_TRX_ID,直到找到满足条件的DB_TRX_ID,这个DB_TRX_ID所在的旧记录就是当前事务能看到的最新老版本数据。

Read View中的三个全局属性:
(1)trx_list:一个数值列表,用来维护Read View生成时刻系统正活跃的事务ID(1,2,3)。
(2)up_limit_id:记录trx_list列表中事务ID最小的ID(1)。
(3)low_limit_id:Read View生成时刻系统尚未分配的下一个事务ID(4)。

具体的比较规则如下:
(1)首先比较DB_TRX_ID < up_limit_id,如果小于,则当前事务能看到DB_TRX_ID所在的记录,如果大于等于进入下一个判断。
(2)接下来判断DB_TRX_ID >= low_limit_id,如果大于等于则代表DB_TRX_ID所在的记录在Read View生成后才出现的,那么对于当前事务肯定不可见,如果小于,则进入下一步判断。
(3)判断DB_TRX_ID是否在活跃事务中,如果在,则代表在Read View生成时刻,这个事务还是活跃状态,还没有commit,修改的数据,当前事务也是看不到,如果不在,则说明这个事务在Read View生成之前就已经开始commit,那么修改的结果是能够看见的。

三、MVCC的整体处理流程

假设有四个事务同时在执行,如下图所示:
在这里插入图片描述
从上述表格中,我们可以看到,当事务2对某行数据执行了快照读,数据库为该行数据生成一个ReadView视图,可以看到事务1和事务3还在活跃状态,事务4在事务2快照读的前一刻提交了更新,所以,在Read View中记录了系统当前活跃事务1,3,维护在一个列表中。同时可以看到up_limit_id的值为1,而low_limit_id为5,如下图所示:
在这里插入图片描述
在上述的例子中,只有事务4修改过该行记录,并在事务2进行快照读前,就提交了事务,所以该行当前数据的undolog如下所示:
在这里插入图片描述
当事务2在快照读该行记录的是,会拿着该行记录的DB_TRX_ID去跟up_limit_id、lower_limit_id和活跃事务列表进行比较,判读事务2能看到该行记录的版本是哪个。

具体流程如下:
(1)先拿该行记录的事务ID-4去跟Read View中的up_limit_id-1相比较,判断是否小于,通过对比发现不小于,所以不符合条件。
(2)继续判断事务4是否大于等于low_limit_id-5,通过比较发现也不大于,所以不符合条件。
(3)继续判断事务4是否处理trx_list列表中,发现不再次列表中,那么符合可见性条件。所以事务4修改后提交的最新结果对事务2的快照是可见的,因此,事务2读取到的最新数据记录是事务4所提交的版本,而事务4提交的版本也是全局角度的最新版本。

如下图所示:
在这里插入图片描述

四、RC、RR级别下的InnoDB快照读有什么不同

因为Read View生成时机的不同,从而造成RC(读未提交)、RR(读已提交)级别下快照读的结果的不同。

1、RR(读已提交)级别

在RR(读已提交)级别下,某个事务对某条记录的第一次快照读会创建一个快照即Read View,将当前系统活跃的其他事务记录起来,此后在调用快照读的时候,还是使用的是同一个Read View,所以只要当前事务在其他事务提交更新之前使用过快照读,那么之后的快照读使用的都是同一个Read View,所以对之后的修改不可见。

2、RR(读已提交)级别

在RR(读已提交)级别下,快照读生成Read View时,Read View会记录此时所有其他活动和事务的快照,这些事务的修改对于当前事务都是不可见的,而早于Read View创建的事务所做的修改均是可见。

总结:在RC(读未提交)隔离级别下,是每个快照读都会生成并获取最新的Read View。而在RR(读已提交)隔离级别下,则是同一个事务中的第一个快照读才会创建Read View,之后的快照读获取的都是同一个Read View。

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

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

相关文章

最新!yolov10+deepsort的目标跟踪实现

目录 yolov10介绍——实时端到端物体检测 概述 主要功能 型号 性能 方法 一致的双重任务分配&#xff0c;实现无 NMS 培训 效率-精度驱动的整体模型设计 提高效率 精度提升 实验和结果 比较 deepsort介绍&#xff1a; yolov10结合deepsort实现目标跟踪 效果展示…

.NET周刊【9月第1期 2024-09-01】

国内文章 【音视频通话】使用asp.net core 8vue3 实现高效音视频通话 https://www.cnblogs.com/1996-Chinese-Chen/p/18384394 该文章描述了使用SRS实现音视频通话和共享桌面的经验。从最初使用nginx的RTMP到研究SRS和ZLMediaKit的过程&#xff0c;再到最终实现功能的详细步…

TF | SD 卡出现无法删除的文件,乱码文件该如何处理 macOS

TF | SD 卡出现无法删除的文件&#xff0c;乱码文件该如何处理 macOS 一、问题描述 最近手头有张用在 Miyoo 掌机上的游戏 TF 卡&#xff0c;在macOS 系统下在回收站中出现了几个特殊文件名的文件&#xff0c;始终无法删除。 二、试着解决 我试过了网上的所有方法都无法删除…

RuoYi-Cloud 部署与配置 [CentOS7]

静态IP设置 # 修改网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33# 修改文件内容 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOstatic IPADDR192.168.18.130 NETMASK255.255.255.0 GATEWAY192.168.18.2 DEFROUTEyes IPV4_FAILURE_FATALno IPV6INIT…

Electron桌面应用与文件路径处理:从Git、SourceTree到TortoiseGit的安装与配置

更多内容前往个人网站&#xff1a;孔乙己大叔 在开发Electron桌面应用程序时&#xff0c;正确处理文件路径是一个至关重要的环节。特别是当涉及到需要调用外部程序&#xff08;如Git、SourceTree或TortoiseGit&#xff09;时&#xff0c;确保这些程序安装在正确的位置&#xff…

@Tanstack/vue-query 的使用介绍

Tanstack/vue-query 的使用介绍 前言 在今年的vue conf 会议上&#xff0c;提到了vue-query这个库&#xff0c;这里对它的基本使用做一个介绍。 会议资料地址&#xff1a; https://vueconf.cn/ Tanstack-query的前身是react-query&#xff0c;是一个本地的服务端状态管理的库…

3.6 逻辑运算

&#x1f393; 微机原理考点专栏&#xff08;通篇免费&#xff09; 欢迎来到我的微机原理专栏&#xff01;我将帮助你在最短时间内掌握微机原理的核心内容&#xff0c;为你的考研或期末考试保驾护航。 为什么选择我的视频&#xff1f; 全程考点讲解&#xff1a;每一节视频都…

wpf prism 《3》 弹窗 IOC

传统的弹窗 这种耦合度高 new 窗体() . Show(); new 窗体() . ShowDialog(); 利用Prism 自动的 IOC 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 》》否…

【C语言】十六进制、二进制、字节、位、指针、数组

【C语言】十六进制、二进制、字节、位 文章目录 [TOC](文章目录) 前言一、十六进制、二进制、字节、位二、变量、指针、指针变量三、数组与指针四、指针自加运算五、二维数组与指针六、指向指针的指针七、指针变量作为函数形参八、函数指针九、函数指针数组十、参考文献总结 前…

系统功能性能优化:从问题定位到解决方案的系统性分析

引言 在现代软件系统中&#xff0c;性能优化是确保系统稳定、响应迅速和资源高效利用的关键。面对复杂的系统架构和业务逻辑&#xff0c;进行性能优化往往需要遵循一系列系统性的步骤&#xff0c;以确保问题被准确识别&#xff0c;解决方案被有效实施。以下是一套专业的系统功…

(四)Kafka离线安装 - Kafka下载及安装

Kafka官方下载地址&#xff1a;Apache Kafka 这时候下载安装版本。 我这里的安装目录在 /usr/local/ cd /usr/local/# 创建目录 mkdir kafka cd kafka mkdir kafka_log 把下载的压缩包&#xff0c;放入到/usr/local/kafka/目录下&#xff0c;解压。 # 解压 tar -zxvf kafka…

前端踩坑记录:javaScript复制对象和数组,不能简单地使用赋值运算

问题 如图&#xff0c;编辑table中某行的信息&#xff0c;发现在编辑框中修改名称的时候&#xff0c;表格中的信息同步更新。。。 检查原因 编辑页面打开时&#xff0c;需要读取选中行的信息&#xff0c;并在页面中回显。代码中直接将当前行的数据对象赋值给编辑框中的表单对…

[从0开始AIGC][LLM]:LLM中Encoder-Only or Decoder-Only?为什么主流LLM是Decoder-Only?

LLM中Encoder-Only or Decoder-Only & 为什么主流LLM是Decoder-Only&#xff1f; 文章目录 LLM中Encoder-Only or Decoder-Only & 为什么主流LLM是Decoder-Only&#xff1f;1. 什么是Encoder-only、Decoder-Only2. 为什么当前主流的LLM都是Decoder-only的架构低秩问题 …

秋招/春招投递公司记录表格

最近在准备秋招&#xff0c;在各个平台投递秋招简历&#xff0c;什么官网&#xff0c;邮箱&#xff0c;boss&#xff0c;应届生各个平台上&#xff0c;投递的平台比较多&#xff0c;比较乱&#xff0c;因此自己想将这些平台投递记录都收集到一个表格上&#xff0c;所以在腾讯文…

bladeX默认审批流flowable如何设置

下面就是流程图必须得写 ${taskUser} 你要配什么 就给审批流的service传什么

VSCode必备插件!快看过来!

同学同学&#xff0c;你是不是也很头疼VSCode不知道安装什么插件啊&#xff1f;尤其是萌新小白&#xff0c;更是一头雾水&#xff0c;那就快来一起看看吧~我帮你整理了一些非常实用的插件&#xff0c;安装上它们&#xff0c;你的开发体验会大大提升&#xff01; 1. Chinese (S…

Call openai-node in the backend or call https in the frontend?

题意&#xff1a;在后端调用 openai-node 还是在前端调用 https&#xff1f; 问题背景&#xff1a; I have a web application by ReactJS and Nodejs. This application calls OpenAI APIs. 我有一个使用 ReactJS 和 Node.js 开发的 Web 应用程序。这个应用程序调用 OpenAI …

零基础入门转录组数据分析——预后模型之lasso模型

零基础入门转录组数据分析——预后模型之lasso模型 目录 零基础入门转录组数据分析——预后模型之lasso模型1. 预后模型和lasso模型基础知识2. lasso预后模型&#xff08;Rstudio&#xff09;——代码实操2. 1 数据处理2. 2 构建lasso预后模型2. 3 提取Lasso预后基因2. 4 计算风…

Pyqt5高级技巧:多线程任务、窗体交互、常用控件介绍(含基础Demo)

目录 一、多线程任务和多窗体交互 二、增删改查Demo 三、UI设计 【css效果代码对照表】 【实现效果】 【实现代码】 【常见问题】 Q1&#xff1a;工具栏怎么加&#xff0c;资源图片怎么加 Q2&#xff1a;控件被背景染色怎么办&#xff1f; Q3&#xff1a;QTdesigner有…

LVS的加权轮询算法

http://kb.linuxvirtualserver.org/wiki/Weighted_Round-Robin_Scheduling 加权轮循调度是为了更好地处理不同处理能力的服务器。每个服务器都可以被分配一个权重&#xff0c;一个表示处理能力的整数值。权值较高的服务器比权值较低的服务器首先接收到新连接&#xff0c;权值较…