MySQL事务MVCC详解

news2025/7/18 13:38:52

一、概述

MVCC (MultiVersion Concurrency Control) 叫做多版本并发控制机制。主要是通过数据多版本来实现读-写分离,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读,从而提高数据库并发性能。

MVCC只在已提交读(Read Committed)和可重复读(Repeatable Read)两个隔离级别下工作,其他两个隔离级别和MVCC是不兼容的。因为未提交读,总数读取最新的数据行,而不是读取符合当前事务版本的数据行。而串行化(Serializable)则会对读的所有数据多加锁。

主要思想是:InnoDB通过undo log保存每条数据的多个版本,并且能够找回数据历史版本提供给用户读,每个事务读到的数据版本可能是不一样的。在同一个事务中,用户只能看到该事务创建快照之前已经提交的修改和该事务本身做的修改。

二、当前读和快照读

  • 快照读:读取的是历史数据,不加锁的简单 Select 都属于快照读。
select * from user where id = 1;
  • 当前读:读取的是最新数据,而不是历史的数据,加锁的 SELECT,或者对数据进行增删改都会进行当前读。
SELECT * FROM user LOCK IN SHARE MODE;
SELECT * FROM user FOR UPDATE;
INSERT INTO user values ...
DELETE FROM user WHERE ...
UPDATE user SET ...

三、MVCC 与快照读的关系

MVCC 多版本并发控制是维持一个数据的多个版本,使得读写操作没有冲突,而这只是一个抽象概念。而快照读就是 MySQL 实现 MVCC 理想模型的其中一个非阻塞读功能,快照读所读取的就是MVCC维持的多版本数据中去某个版本数据。

四、MVCC 优点

  1. 提供多版本数据,在并发读写数据库时,读写操作互不影响,提高了数据库并发读写的性能。
  2. 可以解决脏读,幻读,不可重复读等事务隔离问题。

五、MVCC 实现原理

主要是依赖每一行记录中2个隐藏字段、undo log版本链 以及 ReadView。

1. 行记录的隐藏字段
  1. trx_id:操作这个数据的事务 ID,也就是最后一个对数据插入或者更新的事务 ID 。
  2. roll_ptr:回滚指针,指向这个记录的 Undo Log 信息。
  3. row_id:隐藏的行 ID ,用来生成默认的聚集索引。如果创建数据表时没指定聚集索引,这时 InnoDB 就会用这个隐藏 ID 来创建聚集索引。
2. undo log版本链

多个事务并行操作某一行数据时,不同事务对该行数据的修改会产生多个版本,然后通过回滚指针(roll_pointer),连成一个链表,这个链表就称为版本链。(其实undo log 版本链的节点在事务提交之后可能是会 purge 线程清除掉的)

(1)首先开启第一个事务,事务id为1,通过insert语句往表中插入一条新记录如下:
在这里插入图片描述
由于是新插入的记录,因此它的roll_pointer指向的undo log为空。

(2)接着开启第二个事务,事务id为2,更新该行记录的name为Tom。
在这里插入图片描述

  • 在第二个事务修改该行记录时,数据库会先对该行加排他锁;
  • 然后把该行数据拷贝到 undo log 中,作为旧版本记录;
  • 拷贝完毕后,再修改该行name为Tom,并且修改隐藏字段trx_id为当前事务的id, 回滚指针roll_pointer指向拷贝到 undo log 的副本记录,既表示我的上一个版本就是它。
  • 事务提交后,释放锁。

(3)再开启第三个事务,事务id为3,修改改行记录的age为25。
在这里插入图片描述

  • 在第三个事务修改该行记录时,数据库会先对该行加排他锁;
  • 然后把该行数据拷贝到 undo log 中,作为旧版本记录;
  • 拷贝完毕后,再修改该行age为25,并且修改隐藏字段trx_id为当前事务的id, 回滚指针roll_pointer指向拷贝到 undo log 的副本记录,既表示我的上一个版本就是它。
  • 事务提交后,释放锁。
3.ReadView

Read View 就是事务进行 “快照读” 操作时候生产的 “读视图”,在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的 ID。主要是用来做可见性判断的,即当我们某个事务执行快照读的时候,当前事务能够看到undo log版本链上的哪个版本数据。

(1)ReadView中主要属性

  1. trx_ids:当前系统中那些活跃(未提交)的读写事务ID,它数据结构为一个List。(trx_ids中的活跃事务不包括:当前事务自己)。
  2. min_trx_id:trx_ids中最小的事务id。
  3. max_trx_id:预分配事务编号,MySQL即将为下一个事务分配的事务id。
  4. creator_trx_id: 表示生成该 ReadView 的事务的 事务id。

(2)ReadView可见性判断规则

  1. 判断 trx_id = creator_trx_id,如果条件成立,则说明当前事务与进行select快照读的事务是同一个事务,那么该select是可以读取到该trx_id对应的版本;如果条件不成立,继续往下判断其他条件。
  2. 判断 trx_id < min_trx_id,如果条件成立,则说明当前事务是在进行select快照读的事务之前就已经提交了,那么该select是可以读取到该trx_id对应的版本;如果条件不成立,继续往下判断其他条件。
  3. 判断 trx_id > max_trx_id,如果条件成立,则说明当前事务是在进行select快照读的事务之后才创建的,那么该select是肯定读取不到该trx_id对应的版本;如果条件不成立,则继续往下判断其他条件。
  4. 判断 min_trx_id < trx_id < max_trx_id,如果条件成立,则说明当前事务可能在活跃的事务中,需要再判断下trx_id是否在trx_ids中,如果不在,则说明当前事务已经提交过了,那么该select就可以读取到该trx_id对应的版本;否则说明当前事务还未提交,该select也就无法读取到该trx_id对应的版本。

(3)已提交读(RC)与可重复读(RR)级别下的快照读
RC 隔离级与RR隔离级生成Read View 的时机是不同的,因为也造成了两者快照读的结果的不同。在 RC 隔离级别下,是每个快照读都会生成并获取最新的 Read View;而在 RR 隔离级别下,则是同一个事务中的第一个快照读才会创建 Read View, 之后的快照读获取的都是同一个 Read View。

undo log版本链:
在这里插入图片描述
ReadView创建实时机:
在这里插入图片描述

解析:
(1)RC级别下:
在事务D中的第一个select语句执行时,生成的ReadView中,当前系统中那些活跃(未提交)的读写事务有{3,4},创建ReadView的事务id为5,活跃事务中最新事务id为3,预分配的事务id为6。再根据undo log版本链依次与ReadView的可见性判断规则进行对比,判断哪个版本是可见的。例如:

  • 先对版本链最新的一个版本trx_id = 4进行判断:
    1.先判断 trx_id = creator_trx_id:creator_trx_id = 5,trx_id = 4,条件不成立,暂时无法证明该版本相对于当前select可见,则继续根据其他规则进行判断。
    2.继续判断 trx_id < min_trx_id:min_trx_id = 3,trx_id = 4,条件不成立,也暂时无法证明该版本相对于当前select可见,则继续根据其他规则进行判断。
    3.继续判断 trx_id > max_trx_id:max_trx_id = 6,trx_id = 4,条件不成立,也暂时无法证明该版本相对于当前select可见,则需要继续据其他规则进行判断。(如果该条件成立,则可以证明该版本相对于当前select肯定是不可见的)
    4.继续判断 min_trx_id < trx_id < max_trx_id:条件成立,说明当前事务可能在活跃的事务中,需要再判断下trx_id是否在trx_ids中,trx_id = 4在活跃的事务中,也就是当前事务还未提交,那么该select也就无法读取到该版本的数据。
    所有可见性规则判断完毕,最终得出版本链中最新的一个事务C这个版本在事务D中的第一个select语句是不可见的。
  • 再对版本链中trx_id = 3 按照上述的可见性规则依次判断:最终得出该版本在事务D中的第一个select语句也是不可见的。
  • 再对版本链中trx_id = 2 按照上述的可见性规则依次判断:最终得出该版本在事务D中的第一个select语句也是可见的。

在事务D中的第二个select语句执行时,会重新生成一个新的ReadView,此时系统中那些活跃(未提交)的读写事务有{4},创建ReadView的事务id为5,活跃事务中最新事务id为4,预分配的事务id为6。再根据undo log版本链依次与ReadView的可见性判断规则进行对比,可以得出最终该select语句的可见版本为 trx_id = 3 和 trx_id = 2,与第一个select语句查询的可见版本不一样。这也是为什RC隔离级别下,同一事务中多次使用快照读查询时会产生查询结果不一致的问题。

(2)RR级别下:
在事务D中的第一个select语句执行时,生成一个ReadView与RC级别是一样的,所以最终得到的可见版本也是只有 trx_id = 2。但是在事务D中的第二个select语句执行时,RR级别不会再生成新的ReadView,而是直接复用第一次生的的那个ReadView,所以最终判断下来,第二个select语句的可见版本也只有 trx_id = 2。这也就是为什么RR级别下同一事务中多次使用快照读查询时结果都是相同的原因。如何在事务中使用了当前读,则后面的快照读不会再复用之前的ReadView,而是重新生成一个新的ReadView,这也RR级别下无法解决幻读的原因。

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

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

相关文章

CCF CSP认证 历年题目自练Day34

题目一 试题编号&#xff1a; 202303-1 试题名称&#xff1a; 田地丈量 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 512.0MB 问题描述&#xff1a; 问题描述 西西艾弗岛上散落着 n 块田地。每块田地可视为平面直角坐标系下的一块矩形区域&#xff0c;由左下角坐标 (x1,…

KNN-近邻算法 及 模型的选择与调优(facebook签到地点预测)

什么是K-近邻算法&#xff08;K Nearest Neighbors&#xff09; 1、K-近邻算法(KNN) 1.1 定义 如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别&#xff0c;则该样本也属于这个类别。 来源&#xff1a;KNN算法最早是由Cover和Hart提…

【网络协议】聊聊从物理层到MAC层 ARP 交换机

物理层 物理层其实就是电脑、交换器、路由器、光纤等。组成一个局域网的方式可以使用集线器。可以将多台电脑连接起来&#xff0c;然后进行将数据转发给别的端口。 数据链路层 Hub其实就是广播模式&#xff0c;如果A电脑发出一个包&#xff0c;B、C电脑也可以收到。那么数据…

zk的二阶段提交图解

第一阶段&#xff1a;每次的数据写入事件作为提案广播给所有Follower结点&#xff1b;可以写入的结点返回确认信息ACK&#xff1b;第二阶段&#xff1a;Leader收到一半以上的ACK信息后确认写入可以生效&#xff0c;向所有结点广播COMMIT将提案生效。

Unity 实现一个FPS游戏的全过程

Unity是一款功能强大的游戏引擎&#xff0c;它提供了各种各样的工具和功能&#xff0c;以帮助开发者轻松地创建精美的3D游戏和应用程序。在本文中&#xff0c;我们将使用Unity实现一个FPS游戏的全过程&#xff0c;从场景设计、角色控制、敌人AI到最终的打包发布。 对啦&#x…

开源项目汇总

element-plus 人人开源 人人开源 多租户 若依 jeecg https://gitee.com/jeecg/jeecg?_fromgitee_search#https://gitee.com/link?targethttp%3A%2F%2Fidoc.jeecg.com jeeplus JeePlus快速开发平台 j2eefast Sa-Plus

地震勘探原理部分问题解答

1、二维/三维&#xff08;陆地/海洋&#xff09;地震勘探&#xff0c;炮点&#xff08;激发点&#xff09;和检波点&#xff08;接收点&#xff09;的排布位置如何&#xff1f;画图作答&#xff1f; &#xff08;1&#xff09;陆地地震勘探 二维陆地地震野外采集&#xff1a;震…

过滤器(Filter)和拦截器(Interceptor)有什么不同?

过滤器&#xff08;Filter&#xff09;和拦截器&#xff08;Interceptor&#xff09;是用于处理请求和响应的中间件组件&#xff0c;但它们在实现方式和应用场景上有一些不同。 实现方式: 过滤器是Servlet规范中定义的一种组件&#xff0c;通常以Java类的形式实现。过滤器通过在…

Python文件共享+cpolar内网穿透:轻松实现公网访问

文章目录 1.前言2.本地文件服务器搭建2.1.Python的安装和设置2.2.cpolar的安装和注册 3.本地文件服务器的发布3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 数据共享作为和连接作为互联网的基础应用&#xff0c;不仅在商业和办公场景有广泛的应用&#…

yolov7改进优化之蒸馏(一)

最近比较忙&#xff0c;有一段时间没更新了&#xff0c;最近yolov7用的比较多&#xff0c;总结一下。上一篇yolov5及yolov7实战之剪枝_CodingInCV的博客-CSDN博客 我们讲了通过剪枝来裁剪我们的模型&#xff0c;达到在精度损失不大的情况下&#xff0c;提高模型速度的目的。上一…

6.6 图的应用

思维导图&#xff1a; 6.6.1 最小生成树 ### 6.6 图的应用 #### 主旨&#xff1a;图的概念可应用于现实生活中的许多问题&#xff0c;如网络构建、路径查询、任务排序等。 --- #### 6.6.1 最小生成树 **概念**&#xff1a;要在n个城市中建立通信联络网&#xff0c;则最少需…

【Mysql】Innodb数据结构(四)

概述 MySQL 服务器上负责对表中数据的读取和写入工作的部分是存储引擎 &#xff0c;而服务器又支持不同类型的存储引擎&#xff0c;比如 InnoDB 、MyISAM 、Memory 等&#xff0c;不同的存储引擎一般是由不同的人为实现不同的特性而开发的&#xff0c;真实数据在不同存储引擎中…

如何让大模型自由使用外部知识与工具

本文将分享为什么以及如何使用外部的知识和工具来增强视觉或者语言模型。 全文目录&#xff1a; 1. 背景介绍 OREO-LM: 用知识图谱推理来增强语言模型 REVEAL: 用多个知识库检索来预训练视觉语言模型 AVIS: 让大模型用动态树决策来调用工具 技术交流群 建了技术交流群&a…

微信小程序会议OA系统

Flex弹性布局 Flex弹性布局是一种 CSS3 的布局模式&#xff0c;也叫Flexbox。它可以让容器中的元素按一定比例自动分配空间&#xff0c;使得它们在不同宽度、高度等情况下仍能保持整齐和密集不间隙地排列。 在使用Flexbox弹性布局时&#xff0c;首先需要创建一个容器和若干个…

JNDI-Injection-Exploit工具安装

从github上下载安装 git clone https://github.com/welk1n/JNDI-Injection-Exploit.git 打开 cd JNDI-Injection-Exploit 编译安装&#xff0c;Maven入门百科_maven中quickstart是什么意思-CSDN博客 mvn clean package -DskipTests 因为提示mvn错误&#xff0c;解决下…

Spring中Setter注入详解

目录 一、setter注入是什么 二、setter注入详解 三、JDK内置类型注入方式 3.1 数组类型 3.2 set集合类型 3.3 list集合 3.4 map集合 3.5 properties类型 四、用户自定义类型 一、setter注入是什么 书接上回&#xff0c;我们发现在Spring配置文件中为类对象的属性赋值时&#x…

java SpringBoot基础

目录 SpringBootWeb快速入门前言需求开发步骤创建SpringBoot工程&#xff08;需要联网&#xff09;定义请求处理类运行测试 HTTP协议HTTP概述HTTP-请求协议格式GET方式的请求协议POST方式的请求协议 HTTP-响应协议格式HTTP-协议解析 WEB服务器-Tomcat简介基本使用注意事项 Spri…

智慧渔业方案:AI渔政视频智能监管平台助力水域禁渔执法

一、方案背景 国内有很多水库及河流设立了禁渔期&#xff0c;加强渔政执法监管对保障国家渔业权益、维护渔业生产秩序、保护渔民群众生命财产安全、推进水域生态文明建设具有重要意义。目前&#xff0c;部分地区的监管手段信息化水平低下&#xff0c;存在人员少、职责多、任务…

排序【七大排序】

文章目录 1. 排序的概念及引用1.1 排序的概念1.2 常见的排序算法 2. 常见排序算法的实现2.1 插入排序2.1.1基本思想&#xff1a;2.1.2 直接插入排序2.1.3 希尔排序( 缩小增量排序 ) 2.2 选择排序2.2.1基本思想&#xff1a;2.2.2 直接选择排序:2.2.3 堆排序 2.3 交换排序2.3.1冒…