深入理解MySQL中的MVCC原理及实现

news2024/11/21 0:31:47

目录

什么是MVCC?

MVCC实现原理

Undo Log 日志

InnoDB行格式

undo日志格式

1. insert undo log格式

2. update undo log格式

事务回滚机制

Read View

MVCC案例分析

案例01-读已提交RC隔离级别下的可见性分析

案例02-可重复读RR隔离级别下的可见性分析


什么是MVCC?

        MVCC(Multiversion Concurrency Control)中文名叫多版本并发控制,是现代数据库(包括MySql,Oracle,PostgreSQL等)引擎实现中常用的处理读写冲突的手段。它可以看成行级别锁的一种妥协,它在许多情况下避免了使用锁,同时可以提供更小的开销,目的在于提高数据库高并发场景下的吞吐量。

MVCC实现原理

        MVCC实现原理关键在于数据快照,不同的事务访问不同版本的数据快照,从而实现事务下对数据的隔离级别。虽然说具有多个版本的数据快照,但这并不意味着必须拷贝数据,保存多份数据文件(这样会浪费存储空间),InnoDB通过事务的Undo日志巧妙地实现了多版本的数据快照。

 MVCC的核心问题就是:判断一下版本链中的哪个版本是当前事务可见的!

  • 对于使用 RU 隔离级别的事务来说,直接读取记录的最新版本就好了,不需要Undo log。
  • 对于使用 串行化 隔离级别的事务来说,使用加锁的方式来访问记录,不需要Undo log。
  • 对于使用 RC 和 RR 隔离级别的事务来说,需要用到undo 日志的版本链。

核心思想读不加锁,读写不冲突

实现依赖Undo日志Read View。

Undo Log 日志

        Undo Log:数据库事务开始之前,会将要修改的记录存放到 Undo 日志里,当事务回滚时或者数据库崩溃时,可以利用 Undo 日志,撤销未提交事务对数据库产生的影响。

InnoDB行格式

        我们平时是以记录为单位来向表中插入数据的,这些记录在磁盘上的存放方式也被称为行格式或者记录格式。

        InnoDB一共有四种行格式:Compact、Redundant、Dynamic和Compressed行格式,行格式之间存在差异,但总体可以抽象成以下部分:

  • row_id:如果没有为表显式的定义主键,并且表中也没有定义唯一索引,那么InnoDB会自动为表添加一个row_id的隐藏列作为主键。
  • trx_id:每个事务都会分配一个事务ID,当对某条记录发生变更时,就会将这个事务的事务ID写入tx_id 中。
  • roll_pointer: 回滚指针,本质上就是指向undo log的指针。
undo日志格式

undo log的日志内容是逻辑日志,非物理日志。

  • 物理日志的意思是指具体的把具体某个数据页上的某个偏移量的指改为什么,是具体到物理结构上了,比如redo log就是物理日志。
  • 而逻辑日志只是记录了某条数据的信息是怎么样的,没有到具体的物理磁盘上

根据行为的不同Undo日志分为两种: Insert Undo Log 和 Update Undo Log

1. insert undo log格式

        记录的是insert 语句对应的undo log,Insert 操作的记录只对事务本身可见,对于其它事务此记录是不可见的,所以 Insert Undo Log 可以在 事务提交后直接删除而不需要进行回收操作。

它生成的undo log记录格式如下图:

2. update undo log格式

        记录的是update、delete 语句对应的undo log,是Update或Delete 操作中产生的Undo日志,Update操作会对已经存在的行记录产生影响,为了实现MVCC多版本并发控制机制,因此Update Undo 日志不能在事务提交时就删除,而是在事务提交时将日志放入指定区域,等待 Purge 线程进行最后的删 除操作。

        当确定某个数据的旧版本不再被任何事务需要时(即没有其他事务的read view能够看到这个旧版本的数据),Purge线程就会介入,将这些不再需要的undo日志从链表中删除,并释放相应的空间。

查看purge参数

show variables like '%purge%' ;

它生成的undo log记录格式如下图:

事务回滚机制

表结构

CREATE TABLE `tab_user` (
  `id` int(11) NOT NULL,
  `name` varchar(100) DEFAULT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

1. insert数据:

INSERT INTO `gorgor_user`.`tab_user`( `name`, `age`) VALUES ('刘备', 18);

插入的数据都会生成一条insert undo log,并且数据的回滚指针会指向它。undo log会记录undo log的序号、插入主键的列和值...,那么在进行rollback的时候,通过主键直接把对应的数据删除即可。

2. update数据

update tab_user set age = 30 where id = 1;
update tab_user set name = '雄雄' where id = 1;

 这时会把老的记录写入新的undo log,让回滚指针指向新的undo log,它的undo no是1,并且新的undo log会指向老的undo log(undo no=0),最终形成undo log版本链,如下图所示:

可以发现每次对数据的变更都会产生一个undo log,当一条记录被变更多次时,那么就会产生多条undo logundo log记录的是变更前的日志,并且每个undo log的序号是递增的,那么当要回滚的时候,按照序号依次向前推,就可以找到我们的原始数据了。

那么按照上面的例子,事务要进行回滚,最终得到下面的执行流程:

  1. 通过undo no=2的日志把id=1的数据的name还原成“刘备"
  2. 通过undo no=1的日志把id=1的数据的age还原成"18"
  3. 通过undo no=0的日志把id=1的数据根据主键信息删除

Read View

什么是ReadView?      

        ReadView是张存储事务id的表,主要包含当前系统中有哪些活跃的读写事务,把它们的事务id放到一个 列表中。结合Undo日志的默认字段【事务trx_id】来控制那个版本的Undo日志可被其他事务看见。  

         在可重复读隔离级别,当事务开启,执行任何查询sql时会生成当前事务的一致性视图read-view,该视图在事务结束之前永远都不会变化。如果是读已提交隔离级别在每次执行查询sql时都会重新生成read-view。

        这个视图由执行查询时所有未提交事务id数组(数组里最小的id为min_id)和已创建的最大事务id(max_id)组成,事务里的任何sql查询结果需要从对应版本链里的最新数据开始逐条跟read-view做比对从而得到最终的快照结果。

四个列:

  • m_ids:表示在生成ReadView时,当前系统中活跃的读写事务id列表
  • m_low_limit_id:事务id下限,表示当前系统中活跃的读写事务中最小的事务id,m_ids事务列表 中的最小事务id
  • m_up_limit_id:事务id上限,表示生成ReadView时,系统中应该分配给下一个事务的id值
  • m_creator_trx_id:表示生成该ReadView的事务的事务id

如何判断可见性?

        开启事务执行第一次查询时,首先生成ReadView,然后依据Undo日志和ReadView按照判断可见性, 按照下边步骤判断记录的版本链的某个版本是否可见。

版本链比对规则如下:

  • 如果被访问版本的 trx_id 属性值,小于ReadView中的事务下限id,表明生成该版本的事务在生 成 ReadView 前已经提交,所以该版本可以被当前事务访问。
  • 如果被访问版本的 trx_id 属性值,等于ReadView中的 m_creator_trx_id ,可以被访问。
  • 如果被访问版本的 trx_id 属性值,大于等于ReadView中的事务上限id,在生成 ReadView 后才产 生的数据,所以该版本不可以被当前事务访问。
  • 如果被访问版本的 trx_id 属性值,在事务下限id和事务上限id之间,那就需要判断是不是在 m_ids 列表中。
    • 如果在,说明创建 ReadView 时生成该版本的事务还是活跃的,该版本不可以被访问;
    • 如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问。

循环判断Undo log中的版本链某一的版本是否对当前事务可见,如果循环到最后一个版本也不可见的 话,那么就意味着该条记录对该事务不可见,查询结果就不包含该记录。

当前读与快照读

在MVCC并发控制中,读操作可以分成两类:快照读 (Snapshot Read)与当前读 (Current Read)

  • 快照读:读取的是记录的可见版本 (有可能是历史版本),不用加锁。
  • 当前读:读取的是记录的最新版本,并且当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。常见的 update/insert/delete、还有 select … for update、select … lock in share mode 都是当前读.

MVCC案例分析

表结构

CREATE TABLE `tab_user` (
  `id` int(11) NOT NULL,
  `name` varchar(100) DEFAULT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

插入一条数据

INSERT INTO `gorgor_user`.`tab_user`( `name`, `age`) VALUES ('刘备', 18);
案例01-读已提交RC隔离级别下的可见性分析

 每次读取数据前都生成一个ReadView

在读已提交隔离级别下,T4结果是刘备,T6结果是迪迪,T8结果是张三。

结果分析:

 T3时刻,Undo log 日志版本链图如下:

T4时刻,select 查询会生成当前事务的一致性视图 Read-View。

  • m_ids:表示在生成ReadView时,当前系统中活跃的读写事务id列表
  • m_low_limit_id:事务id下限,表示当前系统中活跃的读写事务中最小的事务id,m_ids事务列表 中的最小事务id
  • m_up_limit_id:事务id上限,表示生成ReadView时,系统中应该分配给下一个事务的id值
  • m_creator_trx_id:表示生成该ReadView的事务的事务id

 从Undo log 日志版本链中,可以根据版本链比对规则比对(规则在上面),trx_id 等于100的事务,是在 m_ids 活跃的读写事务id列表中,不可见. 而 trx_id = 80 的事务比 m_low_limit_id 还小,可见.所以结果为刘备.

T6时刻,select 查询会生成当前事务的一致性视图 Read-View。

从Undo log 日志版本链中,trx_id = 100 比 m_low_limit_id 还小, 所以可见, 结果就为 迪迪.

T8时刻,select 查询会生成当前事务的一致性视图 Read-View。

此时,没有活跃的事务id, 即 m_ids 为空, 意味着再创建 read-view 的那一刻, 没有其他事务是活跃的(即所有其他事务都已提交或未开始). 根据可见性原则,最终结果值为 张三.

案例02-可重复读RR隔离级别下的可见性分析

        在事务开始后第一次读取数据时生成一个ReadView。对于使用 RR 隔离级别的事务来说,只会在第一次执行查询语句时生成一个 ReadView ,之后的查询就不会重复生成了。

代码与执行流程与RC案例完全相同,唯一不同的是事务隔离级别。

T4时刻,select 查询会生成当前事务的一致性视图 Read-View。

从Undo log 日志版本链中,trx_id 等于100的事务,是在 m_ids 活跃的读写事务id列表中,不可见. 而 trx_id = 80 的事务比 m_low_limit_id 还小,可见.所以结果为刘备.

T6时刻,在RR 隔离级别的事务中,ReadView只生成一次,此时ReadView和T4时刻一样.

查询结果还是刘备.同理,T8时刻也一样.

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

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

相关文章

英语词汇小程序小程序|英语词汇小程序系统|基于java的四六级词汇小程序设计与实现(源码+数据库+文档)

英语词汇小程序 目录 基于java的四六级词汇小程序设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大厂码农|毕设布道师&a…

【优选算法】(第十六篇)

目录 连续数组(medium) 题目解析 讲解算法原理 编写代码 矩阵区域和(medium) 题目解析 讲解算法原理 编写代码 连续数组(medium) 题目解析 1.题目链接:. - 力扣(LeetCode&a…

【重学 MySQL】五十一、更新和删除数据

【重学 MySQL】五十一、更新和删除数据 更新数据删除数据注意事项 在MySQL中,更新和删除数据是数据库管理的基本操作。 更新数据 为了更新(修改)表中的数据,可使用UPDATE语句。UPDATE语句的基本语法如下: UPDATE ta…

前端学习第二天笔记 CSS选择 盒子模型 浮动 定位 CSS3新特性 动画 媒体查询 精灵图雪碧图 字体图标

CSS学习 CSS选择器全局选择器元素选择器类选择器ID选择器合并选择器 选择器的优先级字体属性背景属性文本属性表格属性表格边框折叠边框表格文字对齐表格填充表格颜色 关系选择器后代选择器子代选择器相邻兄弟选择器通用兄弟选择器 CSS盒子模型弹性盒子模型父元素上的属性flex-…

Linux 安装 yum

第一步:下载安装包 这里以 CentOS 7 为例 wget https://vault.centos.org/7.2.1511/os/x86_64/Packages/yum-3.4.3-132.el7.centos.0.1.noarch.rpm wget https://vault.centos.org/7.2.1511/os/x86_64/Packages/yum-metadata-parser-1.1.4-10.el7.x86_64.rpm wget…

计算机网络(十) —— IP协议详解,理解运营商和全球网络

目录 一,关于IP 1.1 什么是IP协议 1.2 前置认识 二,IP报头字段详解 三,网段划分 3.1 IP地址的构成 3.2 网段划分 3.3 子网划分 3.4 IP地址不足问题 四,公网IP和私有IP 五,理解运营商和全球网络 六&#xff…

硬件面试(一)

网上别人的硬件面试记录,察漏补缺: 1.骄傲容易被打脸! 励磁电感和谐振电感的比值K大小有什么含义: 励磁电感和谐振电感的比值 KKK 通常用来衡量电路的特性。当 KKK 较大时,表示励磁电感相对于谐振电感较强,可能导致…

力扣题解1870

这道题是一个典型的算法题,涉及计算在限制的时间内列车速度的最小值。这是一个优化问题,通常需要使用二分查找来求解。 题目描述(中等) 准时到达的列车最小时速 给你一个浮点数 hour ,表示你到达办公室可用的总通勤时…

基于SSM的坚果金融投资管理系统、坚果金融投资管理平台的设计与开发、智慧金融投资管理系统的设计与实现、坚果金融投资管理系统的设计与应用研究(源码+定制+开发)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

如何在 Kubernetes 集群中安装和配置 OpenEBS 持久化块存储?

在 Kubernetes 集群中安装和配置 OpenEBS 持久化块存储是一项常见的任务,特别是在需要提供高可用和动态扩展的存储解决方案时。OpenEBS 是一个基于容器的存储解决方案,它允许你在 Kubernetes 集群中实现持久化存储卷(Persistent Volumes&…

Microsoft 发布 PyRIT - 生成式 AI 的红队工具

微软发布了一个名为PyRIT(Python风险识别工具的缩写)的开放访问自动化框架,用于主动识别生成式人工智能(AI)系统中的风险。 这个红队工具旨在“使全球的每个组织都能够负责任地利用最新的人工智能进步进行创新”&…

ros2 自定义工作空间添加source

新建一个工作空间:ros2 create pkg~~~~~~~~~~~~ colcon build之后 ,在install文件夹里面有一个 setup,bash文件 将这个文件添加到 bashrc gedit .bashrc 这样 在一个新终端中可以直接运行ros2 run package name (包名) 可执行…

消息中间件---初识(Kafka、RocketMQ、RabbitMQ、ActiveMQ、Redis)

1. 简介 消息中间件是一种支撑性软件系统,它在网络环境中为应用系统提供同步或异步、可靠的消息传输。消息中间件利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。它支持多种通信协议和数据格式,…

CompletableFuture常用方法

一、获得结果和触发计算 1.获取结果 &#xff08;1&#xff09;public T get() public class CompletableFutureAPIDemo{public static void main(String[] args) throws ExecutionException, InterruptedException{CompletableFuture<String> completableFuture Com…

OpenAI 推理模型 O1 研发历程:团队访谈背后的故事

在 2024 年&#xff0c;OpenAI 推出了具有突破性推理能力的 O1 模型&#xff0c;自发布以来&#xff0c;这款新型 AI 模型引发了技术界的广泛关注。与 GPT-4 等大语言模型不同&#xff0c;O1 不仅具备处理复杂问题的能力&#xff0c;还能模拟人类思考过程&#xff0c;从而提高推…

告别 backtrader!换这个库实施量化回测

作者:老余捞鱼 原创不易,转载请标明出处及原作者。 写在前面的话: 在算法交易的领域,拥有一个强大的回测和策略分析工具至关重要。Vectorbt 已成为最有效且多功能的 Python 库之一。这款开源工具允许交易者在历史数据上测试策略、优化参数,并进行详尽的投资组合和风…

差分(续前缀和)(含一维二维)

题目引入 开发商小 Q 买下了一条街&#xff0c;他想在这条街的一边盖房子。 街道可以抽象为一条数轴&#xff0c;而小 Q 只会在坐标在 1~n 的范围内盖房子。 首先&#xff0c;小 Q 将街上坐标在 1∼ &#x1d45b;1∼ n 范围内的物体全部铲平。也就是说&#xff0c;在正式动工盖…

Kubernetes环境搭建

华子目录 Kubernetes部署说明环境准备工作主机准备harbor搭建k8s集群中的主机名和ip设定k8s集群中设置hosts解析k8s中的所有节点关闭防火墙和selinuxk8s集群中禁用swap分区k8s集群中安装docker-cek8s集群中下载harbor证书k8s集群中配置harbor镜像加速器 k8s节点登录harbor测试 …

当人工智能拥抱餐饮业,传统与创新的交融

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 今天我们要聊一个充满烟火气的行业&#x…

C++进阶知识 AVL树实现

AVL树 1. AVL的概念2. AVL树的实现2.1 AVL树的结构2.2 AVL树的插⼊2.2.1 AVL树插⼊⼀个值的⼤概过程2.2.2 平衡因⼦更新 2.3 旋转2.3.1 旋转的原则2.3.2 右单旋2.3.4 左单旋2.3.5 左右双旋 3.代码实现 1. AVL的概念 • AVL树是最先发明的⾃平衡⼆叉查找树&#xff0c;AVL是⼀颗…