MVCC相关

文章目录

  • 前情要点
    • 基于什么引擎
    • 并发事务产生的问题
    • 不可重复读和幻读区别
    • Next-Key Lock的示例
    • 解决并发事务采用的隔离级别
    • 当前读(Current Read)
    • 快照读(Snapshot Read)
    • 参考
  • MVCC
    • 定义
    • 表里面的隐藏字段
    • 由db_roll_ptr串成的版本链
    • ReadView
    • 可见性算法
    • mvcc的可见性算法为什么要以提交的数据为准则?
    • RC和RR使用MVCC的不同
    • RR级别下是否完全解决幻读问题?
  • 不同隔离级别下的实现原理
  • 特别鸣谢


前情要点

基于什么引擎

mvcc和事务在mysql中都是基于InnoDB引擎下,抛开这个引擎下谈论就没有意义了,因为并不是所有的引擎都支持事务的,例如MyISAM就不支持。

常见的一些引擎:

在这里插入图片描述

并发事务产生的问题

在明白什么是mvcc之前,需要先知道在mysql中两个读的概念;

而在了解什么是当前读和快照读之前,需要先明白在并发事务中常见的问题,如下:

并发事务产生的问题:
1.脏读:

A事务对C数据修改,未提交,B事务读取到这个C数据,并使用。这个修改后的C数据是未提交的,属于脏数据。

2.丢失修改:

A事务对C数据修改,修改为C-1;这个时候B事务也对C数据修改,修改成C-1,最终数据修改为C-1,但是实际上正确修改的数据应该为C-1-1。也就是说A事务的修改被丢失了。

3.不可重复读:

A事务第一次读取C数据10之后,B事务修改C数据为20;这个时候A事务第二次读取C数据为20。不可重复读侧重于更新(update),解决不可重复读是加行级锁(所以更多针对的是表中一行数据)。

4.幻读:

A事务第一次读取C数据总数据为10之后,B事务添加到C数据2条新的数据;这个时候A事务第二次读取C数据总数据为12。幻读主要在于添加(insert)和删除(delete),解决幻读是加间隙锁+Next-Key-Lock(所以更多针对的是(范围内的数据集)整张表的数据

第二点丢失更新属于写写问题,本文不涉及。
从这些读取问题中,可以看到如果在使用读取语句的时候不采取任何措施,那么就意味着我们每次读取到数据并不一定是最新,也不一定是已提交的数据。

不可重复读和幻读区别

在网上能够搜到很多文章,都没准确的说明这两个的区别,对于这两个概念一定要理解透,因为对后续理解mvcc很重要。

不可重复读和幻读的区别:
不可重复读:多次读取同一行数据,读到的值可能不同(其他事务对共享资源的更新)。
解决不可重复读的主要方法是使用 Repeatable Read 隔离级别。主要涉及行级锁,防止同一行数据在同一事务中多次读取时出现不一致

幻读:多次执行相同的范围查询,结果集中的行数可能不同(其他事务对共享资源的增加和删除)。
解决大部分幻读问题方法涉及间隙锁(Gap Lock)和 Next-Key Lock,防止在范围查询中出现新的行或者被删除了行。完全解决幻读的主要方法是使用 Serializable 隔离级别。

以下来自于chatgpt4.0:
在这里插入图片描述

PS: Next-Key Lock:行级锁和间隙锁的组合。它锁定行记录及其前后的间隙,防止在范围查询中出现新的插入或删除操作,从而避免幻读

Next-Key Lock的示例

Next-key Lock的示例如下来自于chatgpt4.0):
在这里插入图片描述

以下是关于间隙锁和Next-Key Lock锁的异同(来自于chatgpt4.0):
在这里插入图片描述

解决并发事务采用的隔离级别

事务隔离级别:

1.读未提交(READ UNCOMMITTED):允许读取尚未提交的数据,可能导致脏读,幻读,不可重复读,丢失更新。

2.读已提交(READ COMMITTED):读取已经提交的数据,阻止了脏读发生,可能导致幻读、不可重复读,丢失更新。

3.可重复读(REPEATABLE READ):解决了脏读,不可重复读的问题。仍然可能发生幻读,丢失更新。

4.串行化(SERIALIZABLE): 解决了脏读,不可重复读,幻读问题,丢失更新。最高等级,最低效率。。。。事务按照顺序执行。

更详细的事务隔离级别可看这个文章:
结合图文一起搞懂MySQL事务、MVCC、ReadView!

当前读(Current Read)

当前读就是读的是当前时刻已提交的数据。

在mysql中,当前读返回的记录都会加上锁,保证其他事务不会再并发的修改这条记录,也就是说在并发事务中读取到的是已经提交的最新的数据。

例如:

select lock in share mode (共享锁),
select for update; update; insert;
delete (排他锁)

以上操作都是属于当前读。在串行化的事务隔离级别下因为事务都加锁,所以读取到的都属于当前读。

快照读(Snapshot Read)

跟当前读相对应的就是快照读,快照读读取到的不是最新的数据,读取到往往是某个快照版本,而不是当前最新的数据。

在 mysql中,快照读不使用锁,而是通过 MVCC 实现。

例如:

– 快照读示例:普通的 SELECT 语句使用快照读
SELECT column1, column2 FROM table_name WHERE condition;

就是在mysql的默认引擎(InnoDB)的默认隔离级别可重复读(Repeatable Read )下,使用select语句不加锁都是快照读。

参考

【MySQL】MVCC详解与MVCC实现原理(MySQL专栏启动)

当前读与快照读

MVCC

定义

MVCC(Multi-Version Concurrency Control):多版本并发控制。常用于数据库管理系统里面无锁的实现并发控制的方法,同时也是事务隔离级别的一种实现方式,提高了事务的并发性能。(Mysql的innoDB存储引擎使用了。Oracle的undo表空间实现MVCC,PostgreSQL也使用了)

在mysql中读已提交(RC,Read Committed)和可重复读(RR,Repeatable Read)都是通过MVCC实现的。

在了解定义之后,要理解MVCC的实现原理需要需要先理解几个概念。

表里面的隐藏字段

在mysql表里面的行数据中,有三个隐藏的列字段,分别是:db_row_id(唯一行号),db_trx_id(事务id),db_roll_ptr(回滚指针)。

此处主要在于下面两个字段:

db_trx_id:
每次⼀个事务对某条聚簇索引记录进⾏改动时,都会把该事务的事务id赋值给trx_id隐藏列

db_roll_ptr:
在undo log日志中存储的每行db_trx_id的上一个版本的回滚指针。每次对某条聚簇索引记录进⾏改动时,都会把旧的版本写⼊到undo⽇志中,然后这个隐藏列就相当于⼀个指针,可以通过它来找到该记录修改前的信息。

ps:
聚簇索引:索引和实际存储的数据在同一个地方,找到索引即找到实际数据值
非聚簇索引::索引和实际存储的数据不在同一个地方,找到索引还需要根据其他索引才能找到实际数据值

以下图片来自于全网最详细MVCC讲解,一篇看懂:
在这里插入图片描述

由db_roll_ptr串成的版本链

上面隐藏字段提到的Undo Log,Undo Log会包含每条更新记录的版本信息,包括旧版本的列数据和db_trx_id(事务id)以及db_roll_ptr(指向上一个版本的指针),这样就组成了一个版本链。

下图来自于:MVCC原理 - 我隔壁是老王 - 博客园
在这里插入图片描述

不同事务或者相同事务对同一记录行的修改,会使该记录行的 undo log 成为一条链表,链首就是最新的记录,链尾就是最早的旧记录

关于UndoLog日志更为详细的内容,请参考:
【MySql进阶】undo日志详解:undo日志结构、undo日志链表、回滚段、undo log原理

ReadView

一致性视图,全称 Read View ,是用来判断版本链中的哪个版本对当前事务是可见的条件,也就是说判断版本链中哪个版本对当前事务是可以读取到的,包含m_ids,m_creator_trx_id,m_low_limit_id,m_up_limit_id。

下图来自于:全网最详细MVCC讲解,一篇看懂 - 知乎
在这里插入图片描述

可见性算法

可见性指的是,当执行一个查询语句(快照读)的时候,当前事务的查询语句可以见到版本链哪条记录。

由隐藏字段db_trx_id(事务id),db_roll_ptr(回滚指针)和Undo Log版本链,Readview就可以实现MVCC了,其对比过程如下:

在这里插入图片描述

1.如果被访问版本的 DB_TRX_ID 属性值小于 Read View 中的 m_up_limit_id 值,说明生成该版本的事务在当前事务生成 Read View 之前已经提交,因此该版本可以被当前事务访问。
2.如果被访问版本的 DB_TRX_ID 属性值位于 Read View 的 m_up_limit_id 和 m_low_limit_id 之间(包括边界),则需要进一步检查 DB_TRX_ID 是否在m_ids 列表中。如果在列表中,说明在创建ReadView时生成该版本的事务仍处于活跃状态,因此该版本不能被访问;如果不在列表中,说明在创建 Read View 时生成该版本的事务已经提交,因此该版本可以被访问。
3.如果被访问版本的 DB_TRX_ID 属性值大于或等于 Read View 中的 m_low_limit_id 值,说明生成该版本的事务在当前事务生成 Read View 之后才提交,因此该版本不能被当前事务访问。
4.如果被访问版本的 DB_TRX_ID 属性值与 Read View 中的 m_creator_trx_id 值相同,表示当前事务正在访问自己所修改的记录,因此该版本可以被当前事务访问。

mvcc的可见性算法为什么要以提交的数据为准则?

从上面可见性算法的对比过程可以看到,其宗旨都是以已经提交了的数据为其是否可见的判断依据的,那么为什么要以这种已经提交的数据为准?

因为mvcc实现的是在可重复读的隔离级别下保证并发事务的有效进行的方式;在可重复读 的隔离级别下,目的就是为了防止脏读即读未提交,不可重复读的并发问题,所以其准则肯定要是读已提交的事务为准。

RC和RR使用MVCC的不同

不同的地方在于可重复读是在第一次查询的时候(快照读)生成的readview,该readview一直被使用,不会生成新的readview;而读已提交则是每次查询的时候(快照读)都生成新的readview从而实现了读已提交。

至于详细的关于其不同的示例,请参考文章中的RC 和 RR 下的 Read View章节:
全网最详细MVCC讲解,一篇看懂

RR级别下是否完全解决幻读问题?

全网最详细MVCC讲解,一篇看懂 - 知乎我看的这篇文章中,是说防止了部分幻读问题,但是没有完全解决幻读问题。这个结论是对的,但是它的示例却是错误的。。。。

在该文章中关于RR 级别下能否防止幻读两个示例如下:
示例1为:
在这里插入图片描述


事务B第一次正常读取(select),而事务B第二次读取使用加锁读取(for update)

示例2为:
在这里插入图片描述


事务B第一次正常读取(select),而事务B第二次读取前使用update语句之后再读取;

这两个示例在我第一次读懂之后,也觉得幻读仍然存在,因为按照第一次查询快照读,第二次查询当前读的机制来看,那么也就意味着即使未提交的事务也可以被当前读读取到。因而读取到最新的数据会导致幻读问题。然而,我还是有点疑心,所以就询问了gpt4.0一样的场景,gpt给出的回答是这两个场景仍然不会有幻读问题。问了好几次,才明白过来它为什么这么说。

需要注意的是,上面所展示的事务示例都是在RR的隔离级别下进行示例;

在事务B的第二次读取时,采用加锁查询也好,update之后再读取也罢;都是在两次读取之间采用了当前读和快照读的不同读取方式,而使用第二次读取采用当前读的方式获取最新的数据看起来会致使读取到不同的数据导致幻读,但是忽略了一个点:未提交的事务对于当前事务来说是不可见的。

无论是加锁也好还是MVCC都是为了实现读取到已经提交的事务,来避免出现并发事务的读取问题。

在上面两个示例里面,事务A的插入对于事务B第二次的加锁读取都不是可见的,也就是说事务B压根不知道事务A的插入,因为当前读在mysql中采用的是加锁的方式去获取最新的已提交数据,试问加锁的情况下怎么可能读取到未提交的事务呢?

那么在RR级别下什么时候会出现幻读问题?

在自增列或无索引列的情况下可能导致幻读问题。(来自于chatgpt4.0)

这个结论是可以闭环的。还记得前面说到不可重复读和幻读的区别的时候提到的Next-Key Lock和间隙锁吗?这两种锁是实现幻读的基础,如果锁出现问题了那么也就意味着幻读问题可能会发生。

这两种锁都是基于索引,其原因(基于chatgpt4.0)如下:
在这里插入图片描述


上图原因总结如下:



1.在无索引的情况下,MySQL 无法有效地使用间隙锁和 Next-Key Lock 来精确锁定范围。只能锁定大范围,不能完全锁住,可能导致幻读问题。



2.自增列的自动递增特性使得未来的插入无法被预锁定。无法预见未来的自增范围,导致新插入的记录不再锁定范围内,只能锁定现有记录和其后的间隙,可能导致幻读问题。



所以可以得出结论如下:
RR级别下没有完全解决幻读问题,当无索引或自增列的情况下会导致间隙锁和Next-Key Lock锁失效的情况,因而会导致幻读问题再发生。

不同隔离级别下的实现原理


不同隔离级别下的锁机制如下:


在这里插入图片描述




总结如下:
1.读未提交:不使用锁,无须其他手段;
2.读已提交:使用行级锁;
3.可重复读:MVCC+ 行级锁 + 间隙锁 + Next-Key Lock
3.可重复读:表级锁

特别鸣谢

结合图文一起搞懂MySQL事务、MVCC、ReadView!

全网最详细MVCC讲解,一篇看懂 - 知乎

MVCC原理

MVCC底层实现原理

Chatgpt4.0

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

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

相关文章

Linux之单机项目部署

1、虚拟机(VMware)创建Linux系统 1.1、创建虚拟机 1.2、配置虚拟机IOS映射文件 1.3、虚拟机内部相关配置 等待加载即可,加载完后会弹出图形化界面,如图: 注意:一般我们做为管理员使用ROOT账号来操作&#x…

数据结构和算法基础(二)

树和二叉树——树的基本概念 树和二叉树——树转二叉树 树和二叉树——查找二叉树(二叉排序树) 树和二叉树——构造霍夫曼树(最优) 树和二叉树——线索二叉树 树和二叉树——平衡二叉树 图——基本概念 1、有向图 2、无向图 3、完…

BGP路由优化

一,拓扑 二,要求 用preva1策略确保R4通过R2到达192.168.10.0/24 ,用AS Path策略,确保R4通过R3到达192.168.11.0/24 置MED策略,确保R4通过R3到达192.168.12.0/24 .用Local Preference策略,确保R1通过R2到达1…

FTP介绍

FTP 1、FTP—文件传输协议 文件传输协议(File Transfer Protocol,FTP)是用于在网络上进行文件传输的一套标准协议,它工作在 OSI 模型的第七层, TCP 模型的第四层, 即应用层, 使用 TCP 传输&…

PCB设计——返回路径

回流基本概念 从电路理论上看,信号是由电流传播的,明确的说是电子的运动,电子流的特性之一就是电子从不在任何地方停留,无论电流流到哪里,必然要回来,因此电流总是在环路中流动,从源到负载然后从…

[手游] 正义对决3

《正义对决3联机版》是一款多人联机的竞技射击游戏,玩家将扮演警方和强盗两个不同的势力,展开一场在庞大都市中的正义之战。强盗一方将在城市内抢劫各处并藏匿,而警方则必须将所有罪犯绳之以法。游戏中,玩家可自由购买众多武器装备…

构建数字未来:探索Web3在物联网中的新视角

引言 随着Web3时代的来临,物联网技术正迎来一场新的变革。在这个数字化时代,Web3所带来的技术创新将为物联网的发展开辟新的视角。本文将深入探讨Web3在物联网领域的应用,揭示其在构建数字未来中的重要性和影响。 Web3与物联网的融合 区块链…

Python设计模式之适配器模式

目录 一、适配器模式 适配器模式的组成部分 适配器模式的种类 应用场景 实现步骤 二、测试例子 一、适配器模式 适配器模式(Adapter Pattern)是一种结构型设计模式,它通过将一个现有接口转换为另一个期望的接口来让不兼容的接口能够合作…

生产物流智能优化系统

对生产调度、物流调度【车辆路径问题、配送中心拣选问题】智能优化算法研究形成系统性程序,逐步开发设计一个智能优化系统【包括:问题说明、实验界面、算法结构和算法程序应用说明】, 当前完成TSP和集送车辆路径的算法程序,程序效…

华为芯片与系统详细梳理--Kirin麒麟 Ascend昇腾 Kunpeng鲲鹏 HarmonyOS鸿蒙 Euler欧拉

华为芯片与系统详细梳理--Kirin麒麟 & Ascend昇腾 & Kunpeng鲲鹏 & HarmonyOS鸿蒙 & Euler欧拉 1 概述2 芯片2.1 整体描述麒麟芯片(To C)【面向智能终端】昇腾芯片【面向AI计算】鲲鹏芯片【面向通用计算】 2.2 细分系列麒麟芯片&#xf…

C#【进阶】迭代器

迭代器 文章目录 1、迭代器概念2、标准迭代器的实现方法3、用yield return 语法糖实现迭代器4、用yield return 语法糖为泛型类实现迭代器 1、迭代器概念 迭代器(iterator) 又称光标(cursor) 是程序设计的软件设计模式 迭代器提供…

【网络技术】【Kali Linux】Wireshark嗅探(十二)NBNS协议报文捕获及分析

往期 Kali Linux 上的 Wireshark 嗅探实验见博客: 【网络技术】【Kali Linux】Wireshark嗅探(一)ping 和 ICMP 【网络技术】【Kali Linux】Wireshark嗅探(二)TCP 协议 【网络技术】【Kali Linux】Wireshark嗅探&…

加入MongoDB AI创新者计划,携手MongoDB共同开创AI新纪元

加入MongoDB AI创新者计划! MongoDB对AI创新和初创企业的支持既全面又广泛!无论您是领先的AI初创企业还是刚刚起步,MongoDB Atlas都是支持您愿景的最佳平台。 AI 初创者计划The AI Startup Track AI初创者计划为早期初创企业提供专属福利&…

hcia datacom学习(10):交换机基础

1.二层交换机工作原理 1.1交换机的5种行为 查看mac地址表的命令为 dis mac-address *一个MAC只能关联在一个接口上,一个接口上可以学习多个MAC *mac地址漂移:mac表中,mac地址的出接口从一个端口变为另一个端口的现象。 造成mac漂移的原因…

【C++提高编程-03】----C++之STL常用容器基础实战

🎩 欢迎来到技术探索的奇幻世界👨‍💻 📜 个人主页:一伦明悦-CSDN博客 ✍🏻 作者简介: C软件开发、Python机器学习爱好者 🗣️ 互动与支持:💬评论 &…

移动云——让每个人都能享受云技术的魅力

一、引言 云技术的起源可以追溯到20世纪60年代和70年代,随着科技的发展,现在早就和所有人息息相关。在云技术的浪潮中,有这么一家厂商通过自己的努力,深耕云计算市场,不仅有各种各样的产品为开发者提供服务&#xff0…

git push后一直卡在在Writing objects:问题

git push后一直卡在Writing objects: 解决:设置 git config --global http.postBuffer 5242880000在执行git push。 一般设置后就可以成功了,后面不用看。 2. 我这里结果又报错: fatal: protocol error: bad line length 8192 MiB | 107.46 …

人工智能应用-实验8-用生成对抗网络生成数字图像

文章目录 🧡🧡实验内容🧡🧡🧡🧡代码🧡🧡🧡🧡分析结果🧡🧡🧡🧡实验总结🧡🧡 &#x1f9…

嵌入式实时操作系统笔记2:UCOS基础知识_UC/OS-III移植(STM32F4)_编写简单的UC/OS-III任务例程(失败.....)

今日学习嵌入式实时操作系统RTOS:UC/OS-III实时操作系统 本文只是个人学习笔记备忘用,附图、描述等 部分都是对网上资料的整合...... 文章主要研究如何将UC/OS-III 移植到 STM32 F407VET6上,提供测试工程下载 (2024.5.21 文章未…

Java web应用性能分析之【高并发之缓存-多级缓存】

说到缓存,作为java开发第一时间想到的是不是上图所示的Redis,又或者是Guava Cache、Caffeine、EhCache这些;Redis作为分布式缓存、其他的可以作为本地缓存。但是作为一名资深开发人员,着眼的层面应该再提升一个级别,从…