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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

编译器 编译过程 compiling 动态链接库 Linking 接口ABI LTO PGO inline bazel增量编译

编译器 编译过程 compiling 动态链接库 Linking 接口ABI LTO PGO Theory Shared Library Symbol Conflicts (on Linux) 从左往右查找:Note that the linker only looks further down the line when looking for symbols used by but not defined in the current lib.Linux 下…

【C++题解】1697. 请输出n~1之间所有的整数

问题:1697. 请输出n~1之间所有的整数 类型:循环 题目描述: 从键盘读入一个整数 n ,请输出 n∼1 之间所有的整数,每行输出 1 个。 比如,假设读入 n5 ,输出结果如下: 5 4 3 2 1 输入&#xff1…

第199题|关于函数的周期性问题|函数强化训练(六)|武忠祥老师每日一题 5月24日

解题思路:解这道题我们要用到下面这个结论 f(x)连续,以T为周期时,原函数以T为周期的充分必要条件是: (A) sin x显然是以π为周期的,我们可以看到并不等于0,根据结论,A的原函数显然不是周期函数。 (B) 的…

移动端仪表盘,支持更多组件

05/22 主要更新模块概览 定位函数 快捷筛选 轨迹图表 时间组件 01 表单管理 1.1 【表单组件】- 表单关联新增支持自定义按钮样式 说明: 表单关联-关联数据按钮,原仅支持默认按钮样式,现增加关联数据按钮自定义功能,满…

【传知代码】掩码自回归编码器法(论文复现)

前言:在探索现代数据科学的前沿领域时,掩码自回归编码器法(Masked Autoencoder,简称MAE)无疑是一个引人注目的亮点。这一技术,凭借其独特的训练机制和卓越的性能,已经在图像识别、自然语言处理以…

《我的阿勒泰》观后感(二、返璞归真也是一种美)

看了李娟的小说《我的阿勒泰》逐渐悟到一个道理,返璞归真也是一种美,没必要每个人的人生三十年的年华,都去追求房子,车子等逐渐贬值的东西。人究竟应该追求怎样的一种活法? 什么是城市化?这是我听到的最好…

osgearth 3.5 vs 2019编译

下载源码 git clone --recurse-submodules https://github.com/gwaldron/osgearth.git 修改配置文件 主要是修改bootstrap_vcpkg.bat,一处是vs的版本,第二处是-DCMAKE_BUILD_TYPERELEASE 构建 执行bootstrap_vcpkg.bat vs中生成安装 vs2019打开bu…

spring boot打的包直接运行

Spring Boot 提供了一个插件 spring-boot-maven-plugin 把程序打包成一个可执行的jar包&#xff0c;直接执行java -jar xxx.jar即可以启动程序 1、引用 spring-boot-maven-plugin插件 <build><plugins><plugin><groupId>org.springframework.boot<…

LED显示屏的智能化发展与未来趋势

摘要&#xff1a;随着智能化技术的飞速发展&#xff0c;LED显示屏行业也迎来了新的变革。本文将探讨LED显示屏的智能化发展方向&#xff0c;包括人屏互动、大屏中控智能化&#xff0c;以及智能LED显示屏在不同领域的应用前景。 1、引言 在智能化浪潮的推动下&#xff0c;LED显示…

GPT-4o: 未来的智能助手

GPT-4o: 未来的智能助手 在这个信息爆炸的时代&#xff0c;人工智能&#xff08;AI&#xff09;已经成为我们生活中不可或缺的一部分。作为OpenAI最新推出的语言模型&#xff0c;GPT-4o不仅继承了前几代模型的优点&#xff0c;还在多个方面进行了显著的提升。本文将带你深入了解…

家政预约小程序03分类管理

目录 1 创建数据源2 搭建导航菜单3 搭建小程序4 设置变量5 变量绑定总结 家政预约小程序里&#xff0c;在首页需要展示家政可以开展的各类业务。我们把业务按照类别进行划分&#xff0c;本篇我们介绍一下管理后台的维护功能以及小程序的展示功能。 1 创建数据源 为了管理和展示…

WiFi蓝牙模块开发配置过程中需要注意的细节

在很多产品的应用场景中&#xff0c;WIFI网络会给我们提供很多便捷&#xff0c;MCU开发中大多使用串口WIFI蓝牙模块来实现产品接入WIFI网络中。   具体的使用模型如下图所示&#xff1a;整个系统涉及到WIFI网络、手机、服务器平台以及我们设计的产品&#xff0c;一个完整的生…

uniapp+php服务端实现苹果iap内购的消耗性项目和非续期订阅项目,前后端代码加逻辑分析

前言&#xff1a;公司的项目app在上架苹果商店时发现人家要求里面的部分购买项目必须使用iap购买的方式&#xff0c;使用原本的微信支付方式审核不给通过&#xff0c;无奈只能重新研究这个东西。做起来还是有点麻烦&#xff0c;主要是网上的文章很少&#xff0c;不能直接硬抄。…

彩信JSON接口对接发送

随着通讯技术的飞速发展&#xff0c;传统的短信已经无法满足人们日益增长的沟通需求。在这样的背景下&#xff0c;群发彩信作为一种更为先进、更为丰富的信息传递方式&#xff0c;逐渐受到了企业和个人的青睐。那么&#xff0c;群发彩信应该怎么对接&#xff0c;又具体有哪些优…

经常碰到的20个等待事件

经常碰到的20个等待事件 oracle等待事件简介 DBA团队维护的部分应用运行在oracle数据库平台&#xff0c;为及时了解数据库的运行情况&#xff0c;需要建立涵盖各个维度的监控体系&#xff0c;包括实例状态、空间使用率、ORA错误等数十项监控指标。这其中有一个有效判断数据库…

Parasoft C++Test软件静态分析操作指南_软件质量度量

系列文章目录 Parasoft CTest软件安装指南 Parasoft CTest软件静态分析操作指南_编码规范/标准检查 Parasoft CTest软件静态分析操作指南_软件质量度量 Parasoft CTest软件静态分析_自动提取静态分析数据生成文档 Parasoft CTest软件单元测试_操作指南 Parasoft CTest软件单元…

Mqtt_Java_IDEA中编写“发布者”和“订阅者”

1Java创建项目 2导入依赖 将下面Mqtt的库名复制到 <dependencies> 下面 <dependency><groupId>org.eclipse.paho</groupId><artifactId>org.eclipse.paho.client.mqttv3</artifactId><version>1.2.5</version></d…

20212416 2023-2024-2 《移动平台开发与实践》第5次作业

百度地图应用 1.实验内容2.实验过程2.1 Android Studio配置2.1. 创建一个Android项目2.2 在项目中本地集成BaiduMap SDK 2.2 编写代码2.2.1 配置AndroidManifest.xml文件2.2.2 编写UI界面布局文件2.2.3 编写主函数代码2.2.4 运行结果 3.学习中遇到的问题及解决4.学习感悟与思考…

netdiscover一键收集子网内的所有信息(KALI工具系列六)

目录 1、KALI LINUX简介 2、netdiscover工具简介 3、在KALI中使用netdiscover 3.1 目标主机IP&#xff08;win&#xff09; 3.2 KALI的IP 4、命令示例 4.1 扫描子网整个网段 4.2 指定网卡进行扫描 4.3 扫描网卡的公共网络 4.4 快速扫描网卡的公共lan地址 4.5 设置…

网络拓扑—DHCP服务配置

文章目录 DHCP服务搭建相关配置细节前提安装DHCP服务 DHCP服务搭建 相关配置细节前提 系统&#xff1a;Windows Server 2003 IP网段&#xff1a;10.0.0.0/24 三台机子&#xff1a; 普通PC机 DHCP服务器 路由器&#xff08;两块网卡&#xff0c;连接内外网&#xff09; //注…