当前位置: 首页 > news >正文

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 采用了乐观锁的方式,读取数据时并不需要加锁,对于写操作,也只锁定必要的行。
  • 解决快照读的问题。当查询数据库在某个时间点的快照时,只能看到这个时间点之前事务提交更新的结果,而不能看到这个时间点之后事务提交的更新结果。

 

 

相关文章:

MySQL 之多版本并发控制 MVCC

MySQL 之多版本并发控制 MVCC 1、MVCC 中的两种读取方式1.1、快照读1.2、当前读 2、MVCC实现原理之 ReadView2.1、隐藏字段2.2、ReadView2.3、读已提交和可重复读隔离级别下,产生 ReadView 时机的区别 3、MVCC 解决幻读4、总结 MVCC(多版本并发控制&…...

优步让一切人工智能化

优步(Uber)的商业模式建立在对数据的颠覆性使用上--通过将双方智能手机的位置数据关联起来,将出租车司机与乘客配对。这意味着,它可以比传统出租车公司更快地安排司机去接乘客,极大地冲击了传统出租车公司的业务。 优步自成立以来&#xff0…...

DeepMind发布新模型Mirasol3B:更高效处理音频、视频数据

Google DeepMind日前悄然宣布了其人工智能研究的重大进展,推出了一款名为“Mirasol3B”的新型自回归模型,旨在提升对长视频输入的理解能力。该新模型展示了一种颠覆性的多模态学习方法,以更综合和高效的方式处理音频、视频和文本数据。 Googl…...

键盘方向键移动当前选中的table单元格,并可以输入内容

有类似于这样的表格&#xff0c;用的<table>标签。原本要在单元格的文本框里面输入内容&#xff0c;需要用鼠标一个一个去点以获取焦点&#xff0c;现在需要不用鼠标选中&#xff0c;直接用键盘的上下左右来移动当前正在输入的单元格文本框。 const currentCell React.u…...

(八)、基于 LangChain 实现大模型应用程序开发 | 基于知识库的个性化问答 (检索 Retrieval)

检索增强生成&#xff08;RAG&#xff09;的整体工作流程如下&#xff1a; 在构建检索增强生成 (RAG) 系统时&#xff0c;信息检索是核心环节。检索是指根据用户的问题去向量数据库中搜索与问题相关的文档内容&#xff0c;当我们访问和查询向量数据库时可能会运用到如下几种技术…...

高效案例检索工具,Alpha案例库智慧检索成为律师检索工具首选

“工欲善其事&#xff0c;必先利其器。”当今&#xff0c;律界同仁需要权衡的问题早已不是“要不要”使用法律科技&#xff0c;而是如何高质量、高效率地使用法律科技工具。在业内人士看来&#xff0c;随着人工智能技术的不断发展&#xff0c;法律行业科技化将成为不可逆转的趋…...

stable diffusion十七种controlnet详细使用方法总结

个人网站&#xff1a;https://tianfeng.space 前言 最近不知道发点什么&#xff0c;做个controlnet 使用方法总结好了&#xff0c;如果你们对所有controlnet用法&#xff0c;可能了解但是有点模糊&#xff0c;希望能对你们有用。 一、SD controlnet 我统一下其他参数&#…...

【机器学习基础】对数几率回归(logistic回归)

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;机器学习 欢迎订阅&#xff01;后面的内容会越来越有意思~ &#x1f4a1;往期推荐&#xff1a; 【机器学习基础】机器学习入门&#xff08;1&#xff09; 【机器学习基…...

团结引擎已全面支持 OpenHarmony 操作系统

Unity 中国宣布与开放原子开源基金会达成平台级战略合作。 据称团结引擎已全面支持 OpenHarmony 操作系统&#xff0c;同时将为 OpenHarmony 生态快速带来更多高品质游戏与实时 3D 内容。Unity 称现在用户可以 “在 OpenHarmony 框架中感受到与安卓和 iOS 同样丝滑的游戏体验”…...

【brpc学习案例实践一】rpc服务构造基本流程

前言 在crpc框架中&#xff0c;brpc简直越用越爽&#xff0c;平时工作中也常用到brpc&#xff0c;一直没来得及总结&#xff0c;抽空写点&#xff0c;也供自己查阅用。下附几个常用学习地址&#xff1a; brpc官网开源地址&#xff1a; https://github.com/luozesong/brpc/blob…...

Redis数据的持久化

Redis的持久化有两种方式&#xff1a; RDB&#xff08;Redis Database&#xff09;和AOF&#xff08;Append Only File&#xff09; 目录 一、RDB 保存方式 2、rdb在redis.conf文件中的配置 二、AOF 1、保存方式 2、aof方式持久化在redis.conf文件中的配置 三、持久化建…...

uniapp App 端 版本更新检测

function checkVersion() { var req { //升级检测数据 appid: plus.runtime.appid, version: plus.runtime.version }; const timestamp Date.parse(new Date()); config.server.query_news uni.reque…...

python用最小二乘法实现平面拟合

文章目录 数学原理代码实现测试 数学原理 平面方程可写为 A x B y C z D 0 AxByCzD0 AxByCzD0 假设 C C C不为0&#xff0c;则上式可以改写为 z a x b y d zaxbyd zaxbyd 则现有一组点 { p i } \{p_i\} {pi​}&#xff0c;则根据 x i , y i x_i,y_i xi​,yi​以及平面…...

SpringCloud微服务:Nacos和Eureka的区别

目录 配置&#xff1a; 区别&#xff1a; ephemeral设置为true时 ephemeral设置为false时&#xff08;这里我使用的服务是order-service&#xff09; 1. Nacos与eureka的共同点 都支持服务注册和服务拉取 都支持服务提供者心跳方式做健康检测 2. Nacos与Eu…...

基于Springboot+Vue的校园在线打印预约系统

基于SpringbootVue的校园在线打印预约系统的设计与实现 (1) 注册功能&#xff1a;允许学生、教职员工注册账户&#xff0c;并提供安全的身份验证机制&#xff0c;确保只有授权用户可以使用系统。 (2) 登录功能&#xff1a;店家或学生可以使用各自账号登录。登录后允许修改用户…...

计算机毕业设计选题推荐-掌心办公微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…...

1.1二分查找

二分查找&#xff0c;主要是针对基本有序的数据来进行查找target。 二分法的思想很简单&#xff0c;因为整个数组是有序的&#xff0c;数组默认是递增的。 1.1 使用条件 用于查找的内容逻辑上来说是需要有序的查找的数量只能是一个&#xff0c;而不是多个 1.2 简介 首先选…...

提升工作效率,打造精细思维——OmniOutliner 5 Pro for Mac

在当今快节奏的工作环境中&#xff0c;如何高效地组织和管理我们的思维和任务成为了关键。而OmniOutliner 5 Pro for Mac正是为此而生的一款强大工具。无论你是专业写作者、项目经理还是学生&#xff0c;OmniOutliner 5 Pro for Mac都能帮助你提升工作效率&#xff0c;打造精细…...

idea显示pom.xml文件漂黄警告 Dependency maven:xxx:xxx is vulnerable

场景&#xff1a; idea警告某些maven依赖包有漏洞或者依赖传递有易受攻击包&#xff0c;如下&#xff1a; 解决&#xff1a; 1、打开idea设置&#xff0c;找到 File | Settings | Editor | Inspections 2、取消上述两项勾选即可...

Linux中安装部署环境(JAVA)

目录 在Linux中安装jdk 包管理器yum安装jdk JDK安装过程中的问题 验证安装jdk 在Linux中安装tomcat 安装mysql 在Linux中安装jdk jdk在Linux中的安装方式有很多种, 这里介绍最简单的方法, 也就是包管理器方法: 包管理器yum安装jdk Linux中常见的包管理器有: yumaptp…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...