MySQL 之多版本并发控制 MVCC

MySQL 之多版本并发控制 MVCC

  • 1、MVCC 中的两种读取方式
    • 1.1、快照读
    • 1.2、当前读
  • 2、MVCC实现原理之 ReadView
    • 2.1、隐藏字段
    • 2.2、ReadView
    • 2.3、读已提交和可重复读隔离级别下,产生 ReadView 时机的区别
  • 3、MVCC 解决幻读
  • 4、总结

       MVCC(多版本并发控制) 没有正式的标准,在不同的 DBMS 中MVCC的实现方式可能不同,本文中讲解的是 InnoDB 中 MVCC 的实现机制(MySQL 其它的存储引擎并不支持 MVCC).

 

1、MVCC 中的两种读取方式

 
       MVCC 在 MySQL InnoDB 中的实现主要是为了提高数据库并发性能,用更好的方式去处理 读-写冲突,做到即使有读写冲突,也能做到 不加锁,非阻塞并发读,而这个读指的就是 快照读,而非当前读。
       当前读实际上是一种加锁的操作,是悲观锁的实现。而MVCC本质是采用乐观锁思想的一种方式。
       快照读和当前读是 MVCC 中的两种读取方式。MVCC 通过快照读和当前读两种方式,在保持事务隔离性的同时,提高了数据库的并发性能

 

1.1、快照读

 
快照读(又叫一致性读),读取的是快照数据,即不加锁的非阻塞读。不加锁的简单 select 都属于快照读。快照读的实现是基于 MVCC(多版本并发控制),在很多情况下,快照读避免了加锁操作,降低了开销。

  • 由于快照读基于 MVCC(多版本并发控制),所以快照读可能读到的并不一定是数据的最新版本,很有可能读的是之前的历史版本数据。
  • 快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读。

 

1.2、当前读

 
       当前读读取的记录是最新版本的数据,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。加锁的 SELECT,或者对数据进行增删改都会进行当前读。比如:

# 共享锁
select * from tb_table lock in share mode;
# 排它锁
select * from tb_table for update;
# 排它锁
insert into tb_table values# 排它锁
delete from tb_table where# 排他锁
update tb_table set

 

2、MVCC实现原理之 ReadView

 
MVCC 的实现依赖于:隐藏字段、undo log、ReadView.

 

2.1、隐藏字段

 
对于InnoDB引擎来说,每个行记录除了记录本身的数据之外,还存在几个隐藏的列。

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

2.2、ReadView

 
       在 MVCC 机制中,多个事务对同一行记录A,进行更新会产生多个历史快照,这个历史快照保存在 undo log 中。当一个事务想要查询 记录A 这行数据时,需要读取哪个版本的记录将是一个问题。ReadView 就可以解决以上 行可见性问题。

在读未提交的隔离级别下事务,查询的数据都是最新版本,所以不需要MVCC。在串行化隔离级别下的事务,InnoDB 规定使用加锁的方式来访问记录,也不需要MVCC。

ReadView 就是事务在使用 MVCC 机制进行快照读操作时产生的读视图。ReadView 主要包含了以下4个重要内容:

  • creator_trx_id,创建该 ReadView 的事务ID.

    只要在对表中的记录做改动时(执行 INSERT、DELETE、UPDATE 这些语句时)才会为事务分配事务id,否则在一个只读事务中的事务id只都默认为0.

  • trx_ids,表示生成 ReadView 时,当前系统中活跃的读写事务的 事务id列表

  • up_limit_id,活跃的事务中最小的事务ID.

  • low_limit_id,表示生成 ReadView 时系统中应该分配给下一个事务的 id 值。low_limit_id 是系统最大的事务ID值.

    low_limit_id 并不是trx_ids 中的最大值,事务ID是递增分配的。比如:现在有ID为1、2、3这三个事务,之后ID为3的事务提交了,那么一个新的读事务在生成 ReadView 时,trx_ids 就包括1 和2,up_limit_id 的值就是1,low_limit_id的值就是4.

ReadView 的规则:在访问某条记录时,需要按照以下步骤(ReadView 的规则)判断记录的某个版本是否可见

  • 如果被访问版本的 trx_id(db_trx_id) 属性值与 ReadView 中的 creator_trx_id 值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
  • 如果被访问版本的 trx_id(db_trx_id) 属性值小于 ReadView 中的 up_limit_id 值,表明生成该版本的事务在当前事务生成 ReadView 前已经提交,所以该版本可以被当前事务访问。
  • 如果被访问版本的 trx_id(db_trx_id) 属性值大于或等于 ReadView 中的 low_limit_id 值,表明生成该版本的事务在当前事务生成 ReadView 后才开启,所以该版本不可以被当前事务访问。
  • 如果被访问版本的 trx_id(db_trx_id) 属性值在 ReadView 的 up_limit_id 和 low_limit_id 之间,就需要判断一下 trx_id 属性值是否在 trx_ids 列表中。
  • 如果在,说明创建 ReadView 时,生成该版本的事务还是活跃的,该版本不可以被访问。
  • 如果不在,说明创建 ReadView时,生成该版本的事务已经被提交,该版本可以被访问。

MVCC 整体操作流程:

查询一条记录时,系统通过MVCC机制查找记录的流程:

  • ① 首先获取事务自己的版本号,也就是事务ID.
  • ② 获取 ReadView.
  • ③ 查询得到的数据,然后与 ReadView 中的事务版本号进行比较。
  • ④ 如果不符合 ReadView 规则,就需要从 undo log 中获取历史快照。
  • ⑤ 最后返回符合规则的数据。

       如果某个版本的数据对当前事务不可见,那就顺着版本链找到下一个版本的数据,继续按照上边的步骤判断可见性,依此类推,直到版本链中的最后一个版本。

InnoDB 中,MVCC 是通过 Undo Log + ReadView 进行数据读取, Undo Log 保存了历史快照,而 Read View 规则帮我们判断当前版本的数据是否可见。

 

2.3、读已提交和可重复读隔离级别下,产生 ReadView 时机的区别

 

  • 在隔离级别为读已提交(Read Commit)时,一个事务中的每一次 SELECT 查询都会重新获取一次 ReadView.

    步骤事务说明
    1begin;
    2select * from tb_table where id > 2;获取一次 ReadView
    3……
    4select * from tb_table where id > 2;获取一次 ReadView
    5commit;
    • 步骤2和步骤4,一样的查询语句,在读已提交的隔离级别下,会分别获取一次 ReadView,如果两次的ReadView 不同,就可能产生不可重复读或者幻读的情况。
  • 当隔离级别为可重复读的时候,一个事务只在第一次 SELECT 时会获取一次 ReadView,而后面所有的 SELECT 都会复用这个 ReadView,所以可以避免不可重复读。
    在这里插入图片描述

 

3、MVCC 解决幻读

 
       使用例子说明 InnoDB 如何解决幻读,以下示例是在InnoDB引擎的可重复读隔离级别下讨论。现在 tb_table 表中已存在一条 主键id = 1 的数据,该条记录隐藏的 db_trx_id = 10。

db_trx_id = 10数据:id = 1,name = 张三NULL

假设现有 事务A 和 事务B 并发执行,事务A 的事务id 为 20,事务B 的事务id 为 30.

  • 步骤 1:事务A 开始第一次查询数据。

    – 事务A 开始第一次查询数据

    select * from tb_table where id >=1;
     
    ① --> 在开始查询前,MySQL 会为事务A产生一个 ReadView,此时 ReadView 的内容如下:trx_ids = [20,30],up_limit_id = 20,low_limit_id = 31,creator_trx_id = 20.
     
    ② --> 执行select * from tb_table where id >=1;查出id=1,db_trx_id= 10的数据,按ReadView机制判断该行数据是否可见。
     
    ③ --> 按 ReadView 机制 该查询出的数据 db_trx_id = 10 ,小于事务A的ReadView 的up_limit_id,故该数据在事务A 开启之前,其他事务已提交,所以该行数据可见。
     
    结论:事务A 的第一次查询,能读到一条数据,id=1,name= 张三。

  • 步骤2:接着事务B(事务id=30),往tb_table 插入两条数据,并提交事务(假设不考虑 gap lock)。

    insert into student(id,name) values (2,'李四')insert into student(id,name) values (3,'王五')

    此时 tb_table 中就要三条数据了,对应的 undo log 如下。
    在这里插入图片描述

  • 步骤3:接着事务A开启第二次查询,由于在可重复读隔离级别下,事务A不会再次生成ReadView.

    – 事务A 开始第二次查询数据

    select * from tb_table where id >=1;
     
    ① --> 此时tb_table中的3条数据都满足 id>=1 的条件,因此会先查出来,然后根据 ReadView 机制,判断每条数据是不是都可以被事务A可见。
     
    ② --> 首先 id = 1 这条数据同步骤1,对事务A可见。
     
    ③ --> 然后是 id = 2 的数据,它的 trx_id = 30,介于 ReadView 的 up_limit_id = 20 和 low_limit_id = 31 之间,需要再次判断 trx_id = 30 是否处于 ReadView 的 trx_ids=[20,30] 数值内。结果在trx_ids数组内,表示 id= 2 这条数据是与事务A 在同一时刻启动的其他事务提交的,所以这条数据不能被事务A可见。
     
    ④ --> 同理,id = 3 这条数据,trx_id 也为 30,因此也不能被事务A 可见。
     
    结论:最终事务A 的第二次查询,只能查询出 id = 1 的这条数据,这和事务A 的第一次查询的结果一样,因此没有出现不可重复读现象

    在这里插入图片描述

注意只靠MVCC不能完全解决幻读问题。虽然MVCC可以提供事务的一致性视图,并保持数据的一致性版本,但它本身并不能防止其他事务插入新的数据。通过结合 next-key locking 和 MVCC,InnoDB 在可重复读隔离级别下解决了幻读问题,确保了事务在多次读取相同范围数据时的一致性

      间隙锁是在 innodb的 可重复读级别才会生效,且 Next-Key Locks 实际上是由间隙锁加行锁实现的MySQL 在 InnoDB 存储引擎下,可重复读的隔离级别下,不存在幻读问题
 

4、总结

 
MVCC(多版本并发控制)的核心点在于 ReadView 的原理,READ COMMITTED、REPEATABLE READ 这两个隔离级别的一个很大不同就是生成 ReadView 的时机不同:

  • READ COMMITTED每一次进行普通 select 操作前,都会生成一个 ReadView.
  • REPEATABLE READ 只在第一次进行普通 select 操作前生成一个 ReadView,之后的查询操作都重复使用这个 ReadView 就好了。

 

MVCC(多版本并发控制)解决的问题

  • 读写之间阻塞的问题。通过 MVCC 可以让读写相互不阻塞,即读不阻塞写,写不阻塞读,可以提升事务并发处理能力。
  • 降低了死锁的概率。因为 MVCC 采用了乐观锁的方式,读取数据时并不需要加锁,对于写操作,也只锁定必要的行。
  • 解决快照读的问题。当查询数据库在某个时间点的快照时,只能看到这个时间点之前事务提交更新的结果,而不能看到这个时间点之后事务提交的更新结果。

 

 

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

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

相关文章

【C++】pow函数实现的伽马变换详解和示例

本文通过原理和示例对伽马变换进行详解,并通过改变变换系数展示不同的效果,以帮助大家理解和使用。 原理 伽马变换是一种用于图像增强的技术,它可以用来提高或降低图像的对比度,常用于医学图像处理和计算机视觉等领域。伽马变换…

node 第十八天 中间件express-session实现会话密钥

express-session 文档 express-session 一个简单的express会话中间件 使用场景 在一个系统中, 需要维持一个临时的与登录态无关的会话密钥 比如登录系统后, 请求某一个接口, 接口的行为与登录态无关, 也就是说任何人对接口的访问…

steam搬砖项目2023年现状分析,到底还能不能做?

关于CSGO游戏搬砖项目的5大认知误区 当前的steam搬砖项目市场正变得混乱不堪。你对该项目的了解程度决定了你是否能在这个生态系统中获得收益。 假设你有100万资金,想要全部投入搬砖事业,但对项目一无所知,只看中收益。即使你有充足的资金&a…

Debian系列的Linux发行版上部署wvp

Debian系列的Linux发行版上部署wvp 环境搭建1.Debian系列的Linux发行版上安装nginx2.安装mysql设置mysql密码修改权限sudo mysql ERROR 1045 (28000): Access denied for user root@localhost (using password: NO)配置相关navicat 连接不上 报错 10061navicat 连接报错 1130 -…

springcloudalibaba-3

一、Nacos Config入门 1. 搭建nacos环境【使用现有的nacos环境即可】 使用之前的即可 2. 在微服务中引入nacos的依赖 <!-- nacos配置依赖 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-…

最新版微信如何打开青少年模式?

最新版微信如何打开青少年模式&#xff1f; 1、将手机微信升级到最新版&#xff0c;并打开后点击底部我的进入&#xff1b; 2、在我的内&#xff0c;找到并点击设置进入&#xff1b; 3、在设置内找到青少年模式&#xff0c;并点击进入开启微信青少年模式&#xff1b; 原文来源…

无菌药品生产(A级区域)--气流流型测试可视化烟雾试验详细介绍

技术背景 无菌药品是指法定药品标准中列有无菌检测项目的制剂和原料药&#xff0c;包括注射剂、眼用制剂、无菌软膏剂、无菌混悬剂等。目前工程中&#xff0c;以注射剂产品为主的厂房占据了很大的比重。 无菌药品生产质量风险管理中&#xff0c;人员及其活动被视为重大的污染…

如何进行手动脱壳

脱壳的目的就是找到被隐藏起来的OEP&#xff08;入口点&#xff09; 这里我一共总结了三种方法&#xff0c;都是些自己的理解希望对你们有用 单步跟踪法 一个程序加了壳后&#xff0c;我们需要找到真正的OEP入口点&#xff0c;先运行&#xff0c;找到假的OEP入口点后&#x…

计算机网络八股文

计算机网络八股文 第一章 计算机网络基础 1.1 OSI 七层参考模型及各自功能 七层参考模式是一个抽象的模型体&#xff0c;不仅包括一系列抽象的术语或概念&#xff0c;也包括具体的协议。 &#xff08;物、数、网、传、会、表、应&#xff09; 物理层&#xff1a;主要定义物…

各类语言真实性能比较列表

这篇文章是我所做或将要做的所有真实世界性能比较的索引。如果你对想要看到的其他真实世界案例有建议&#xff0c;请在评论中添加。 用例 1 — JWT 验证 & MySQL 查询 该用例包括&#xff1a; 从授权头部获取 JWT验证 JWT 并从声明中获取电子邮件使用电子邮件执行 MySQL…

linux上交叉编译qt库

linux上交叉编译qt库 Qt程序从X86平台Linux移植到ARM平台Linux需要做什么 1.在ubuntu上使用qt的源码交叉编译出Qt库 2.将编译好的库拷贝到开发板上并设置相应的环境变量&#xff08;库路径啥的&#xff09; 前两步一劳永逸&#xff0c;做一次就行 3.X86上写好程序代码&…

【开源】基于Vue.js的智能教学资源库系统

项目编号&#xff1a; S 050 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S050&#xff0c;文末获取源码。} 项目编号&#xff1a;S050&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 课程档案模块2.3 课…

分布式与微服务 —— 初始

前言 距今微服务的提出已经过去快十个春秋&#xff0c;网络上的博文讲微服务也是一抓一大把&#xff0c;但是荔枝仍然觉得还是有必要自己梳理一下整个知识体系。在这篇文章中&#xff0c;荔枝将会以一个初学者的角度来切入&#xff0c;从分布式系统和微服务架构引入&#xff0c…

【咖啡品牌分析】Google Maps数据采集咖啡市场数据分析区域分析热度分布分析数据抓取瑞幸星巴克

引言 咖啡作为一种受欢迎的饮品&#xff0c;已经成为我们生活中不可或缺的一部分。随着国内外咖啡品牌的涌入&#xff0c;新加坡咖啡市场愈加多元化和竞争激烈。 本文对新加坡咖啡市场进行了全面的品牌门店数占比分析&#xff0c;聚焦于热门品牌的地理分布、投资价值等。通过…

深度学习交通车辆流量分析 - 目标检测与跟踪 - python opencv 计算机竞赛

文章目录 0 前言1 课题背景2 实现效果3 DeepSORT车辆跟踪3.1 Deep SORT多目标跟踪算法3.2 算法流程 4 YOLOV5算法4.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; *…

MCU内存基础知识

文章目录 一、存储器分类二、C语言内存分区内存区三、STM32启动文件分析四、应用分析 一、存储器分类 RAM&#xff08;Random Access Memory) &#xff1a;掉电之后就丢失数据&#xff0c;读写速度块 ROM (Read Only Memory) &#xff1a;掉电之后仍然可以保持数据 单片机的RA…

Docker部署MinIO对象存储服务器结合Cpolar实现远程访问

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远…

反渗透水处理成套设备有哪些

反渗透水处理成套设备主要包括反渗透装置、预处理系统、控制系统等部分。 反渗透装置&#xff1a;反渗透水处理设备的核心部分&#xff0c;由反渗透膜、压力容器、膜组件等组成。反渗透膜是一种高分子材料制成的半透膜&#xff0c;能够截留水中的溶解盐、有机物、细菌等杂质&a…

buildadmin+tp8表格操作(7)表格的事件监听

buildadmin 中的事件都已经在 baTable类中定义好了。我们一般不会去修改&#xff0c;万一我们要在事件上有所操作&#xff0c; 我们可以通过事件的 前置和后置 钩子函数来处理 那么我们是如何使用这些钩子呢&#xff1f; 我们只需要在 创建对象的时候&#xff0c;定义好这些钩…

场景交互与场景漫游-路径漫游(7)

路径漫游 按照指定的路径进行漫游对一个演示是非常重要的。在osgViewer中&#xff0c;当第一次按下小写字母“z”时&#xff0c;开始记录动画路径;待动画录制完毕&#xff0c;按下大写字母“Z”&#xff0c;保存动画路径文件;使用osgViewer读取该动画路径文件时&#xff0c;会回…