【MySQL】深入解析事务与MVCC

文章目录

      • 1、事务四大特性
        • 1.1、原子性
        • 1.2、一致性
        • 1.3、隔离性
        • 1.4、持久性
      • 2、并发事务带来问题
        • 2.1、脏读
        • 2.2、不可重复读
        • 2.3、幻读
      • 3、事务隔离级别
        • 3.1、读未提交
        • 3.2、读已提交
        • 3.3、可重复读
        • 3.4、串行化
      • 4、MVCC
        • 4.1、InnoDB隐藏字段
        • 4.2、undo log版本链
        • 4.3、ReadView
        • 4.4、MVCC工作流程
        • 4.5、可重复读 MVCC 实现
        • 4.6、读已提交 MVCC 实现

1、事务四大特性

对于Java开发的小伙伴来说,事务这个词并不陌生,当我们在业务代码中涉及到多个DML(非查询)操作时,一般都会使用事务,目的是防止业务操作中途报错,导致业务执行不完整,数据逻辑不正确,所以事务的作用主要是保证了数据的准确性,对于MySQL事务来说,具备原子性、一致性、隔离性、持久性这四大特性,接下来我们依次讲解。

1.1、原子性

原子性指的是:一个事务中的所有操作,要么全部成功,要么全部失败;这个事务特性是通过undo log日志来实现的。当事务执行过程中某个DML操作发生错误,就可以通过undo log的回滚链进行回滚操作,这样就恢复到事务操作之前的状态了,保证了原子性

1.2、一致性

一致性指的是:事务执行前后,数据库中的数据是一致的。例如:A用户和B用户各自有1000存款,A向B转500,最终A存款为500,B存款为1500;而不是A存款为500,B存款还是1000,这就叫事务的一致性。事务的其他三个特性最终保证了事物的一致性

1.3、隔离性

隔离性指的是:数据库中多个事务操作之间不会互相干扰,并发执行的事务之间是隔离的,当多个事务操作同个数据时,事物之间不会造成干扰和影响。对于隔离性是通过MVCC锁机制来实现的(MVCC后续会详细讲解)。

1.4、持久性

持久性指的是:实务操作提交完成之后,MySQL数据是持久化存储到硬盘中的。

2、并发事务带来问题

当多个客户端连接到MySQL数据库时,大概率也会出现同时开启事务操作的场景,一般称之为并发事务;对于并发事务场景来说,就可能出现脏读不可重复读幻读问题,接下来以此解释一下并发事务所带来的这三种情况。

2.1、脏读

脏读指的是:事务A读取到了事务B修改了但未提交的数据。
在这里插入图片描述

2.2、不可重复读

不可重复读指的是:事务A读取到了事务B修改了并提交的数据。
在这里插入图片描述

2.3、幻读

幻读指的是:事务A前后两次查询的数据条数不一样。
在这里插入图片描述

3、事务隔离级别

3.1、读未提交

读未提交指的是:事务A能够读取到事务B修改了但未未提交的数据。跟上面提到的脏读现象是一样的,所以读未提交隔离级别无法避免脏读现象的发生。

3.2、读已提交

读已提交指的是:事务A能读取到事务B修改了并提交的数据。跟上面提到的不可重复读现象是一样的,所以读已提交隔离级别无法避免不可重复读现象的发生,但是可以避免脏读

3.3、可重复读

可重复读指的是:事务开启后,每次读取的数据都是一致的。这是事务默认的隔离级别。所以可重复读解决了脏读、不可重复读现象,但是不能完全避免幻读现象。

3.4、串行化

串行化指的是:单个事物对数据进行操作时,会上读写锁。这样其他事务需要等待该事务操作完毕释放锁后,才可以进行操作。所以串行化可以解决并发事务带来的所有问题,也就是脏读、不可重复读、幻读都能处理。

4、MVCC

MVCC又称为多版本并发控制,该机制是InnoDB存储引擎特有的,它解决了并发事务场景下的读写性能问题,完全不需要加锁。

只有读已提交可重复读这两种隔离级别具备MVCC,并且实现的细节也有些许不同,换句话说读已提交可重复读隔离级别实现是通过MVCC机制来保证的。至于读未提交允许事务A读取事务B未提交的记录,自然就不需要MVCC介入;至于串行化已经通过锁来限制事务的操作是串行的,更不需要MVCC来保障。

MVCC多版本并发控制需要undo log版本链ReadViewroll_pointer来合作实现,接下来我们依次介绍,深入了解一下MVCC是如何工作的。

4.1、InnoDB隐藏字段

对于InnoDB存储引擎来说,它会为MySQL表中每一行数据都设置默认的字段信息,主要有3个:

  • trx_id:当前事务操作id
  • row_id:隐式主键,如果某行记录不存在主键字段,就会生成row_id代替
  • roll_pointer:回滚指针,用于记录undo log回滚地址

在这里插入图片描述

4.2、undo log版本链

undo log记录是用于事务进行回滚操作的,undo log记录通过roll_pointer地址进行连接、回滚,下图中的整个链路就可以理解为undo log版本链,当事务操作需要发生回滚事,就是通过undo log版本链恢复到事务前的状态。
在这里插入图片描述

4.3、ReadView

当事务启动后,MVCC会为查询操作生成ReadView(类似当前数据快照),不过在读已提交可重复读这两种隔离级别,ReadView生成的细节也是不同的(4.5、4.6会详细说说),ReadView组成分为以下四个部分:

  • creator_trx_id:创建该ReadView的事务ID
  • trx_ids:表示在生成当前ReadView时,系统内活跃未提交的事务ID列表
  • min_trx_id:活跃的事务列表中,最小的事务ID
  • max_trx_id:表示在生成当前ReadView时,数据库将要给下个事务分配的ID
4.4、MVCC工作流程

上面提到过,MVCC的工作需要undo log版本链ReadViewroll_pointer来合作实现,接下来我们来看看到底是如何配合完成MVCC。

InnoDB会为每一行记录设置隐藏字段trx_idroll_pointer,表示当前记录的操作事务id回滚指针,undo log记录通过roll_pointer进行连接,构成了undo log版本链。那么此时某个事务的查询操作能看到怎样的结果,要符合以下的规则:

  • 记录 trx_id < ReadView 中 min_trx_id:表示这个版本记录是在创建 ReadView 前提交的事务生成的,所以该版本记录对当前事务可见
  • 记录 trx_id ≥ ReadView 中 max_trx_id:表示这个版本记录是在创建 ReadView 后启动的事务生成的,所以该版本记录对当前事务不可见
  • 记录 trx_id 在 max_trx_id 和 min_trx_id 之间:
    • 记录 trx_id 在 m_ids 中,表示生成该版本记录的活跃事务未提交,该版本的记录对当前事务不可见
    • 记录 trx_id 不在 m_ids 中,表示生成该版本记录的活跃事务已提交,该版本的记录对当前事务可见
4.5、可重复读 MVCC 实现

对于可重复读来说,事务首次select操作前会生成一个ReadView,整个事务操作阶段范围内都会使用这个ReadView

假设现在数据库中有一行记录如下:
在这里插入图片描述
此时开启事务A和事务B,分别如下:
在这里插入图片描述
此时可以看到,由于记录的事务id为1,不论是事务A还是事务B的事务id都是 > 记录的trx_id,所以事务A和事务B都能够读取到这行数据。假设此时事务A将本行记录进行了修改,记录如下:
在这里插入图片描述
此时事务B再次读取记录信息时,就会发现这条记录的事务id为2,在事务B的ReadViewtrx_ids中,说明该记录是活跃的未提交的,那么本次改动对于事务B来说就是不可见的,所以还要顺着undo log版本链找到下一条记录,发现trx_id为1,说明是可见的。

所以可重复读隔离级别通过MVCC解决了不可重复读问题:事务B读取不到事务A修改并提交的数据。

4.6、读已提交 MVCC 实现

对于读已提交来说,事务每次select操作前会生成一个ReadView,后续每次的查询操作都使用最新的ReadView

针对于4.5章节提到那个情况,事务A将数据进行了修改,如下:
在这里插入图片描述
由于读已提交导致事务B每次读数据都会重创建新的ReadView,如下:
在这里插入图片描述
此时可以发现事务A修改提交后的记录trx_id < 事务B的新ReadViewmin_trx_id,所以对于事务B来说就可以看见事务A修改并提交的数据,由于每次查询操作都会创建最新的ReadView,在事务操作期间其他事务提交记录也能够读取到。

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

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

相关文章

fiddler过滤器使用,隐藏图片、js、css请求

如果抓包过程中不想查看图片、js、css请求&#xff0c;或者只想抓某个ip或者某个网页下的请求&#xff0c;可以在过滤器中设置。 &#xff08;1&#xff09;没有开启过滤器 可以看出所有的请求都会抓取&#xff0c;cs、js、图片请求都有 &#xff08;2&#xff09;开启过滤器 …

波奇学Linux:网络套接字

domain:ipv4 还是ipv6 type:面向字节流还是... 虚拟机 云服务器禁止直接bind公网ip 服务器可以有多个ip&#xff0c;如果只绑定一个ip&#xff0c;只能收到来自一个ip的信息 任意地址绑定 关于port的问题 [0,1024]&#xff1a;系统内定的端口号&#xff0c;一般要用固定的应…

基于SpringBoot+MyBatis框架的智慧生活商城系统的设计与实现(源码+LW+部署+讲解)

目录 前言 需求分析 可行性分析 技术实现 后端框架&#xff1a;Spring Boot 持久层框架&#xff1a;MyBatis 前端框架&#xff1a;Vue.js 数据库&#xff1a;MySQL 功能介绍 前台功能拓展 商品详情单管理 个人中心 秒杀活动 推荐系统 评论与评分系统 后台功能拓…

基于Matlab的眼底图像血管分割,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

光速论文能用吗 #媒体#知识分享#学习方法

光速论文是一个非常有效的论文写作、查重降重工具&#xff0c;它的使用非常简单方便&#xff0c;而且功能强大&#xff0c;是每个写作者必备的利器。 首先&#xff0c;光速论文具有强大的查重降重功能&#xff0c;能够快速检测论文中的抄袭部分&#xff0c;帮助作者避免不必要的…

2021年12月更新千言万语汇聚成一张图

今年的双十二几乎不复存在。 11月11日之后&#xff0c;有读者问我要不要等双十二。 现在看来&#xff0c;房东已经没有多余的粮食了&#xff0c;互联网的冬天比以前来得早得多。 进入12月份&#xff0c;公司同事和项目组的合伙人最近讨论的不再是年终奖&#xff0c;而是项目能…

解决mysql问题: this is incompatible with sql_mode=only_full_group_by

今天在部署一趟测试环境的服务&#xff0c;各种配置文件都配好了&#xff0c;启动服务后台报错&#xff0c;解决后记录一下&#xff0c;小伙伴们也可以看看&#xff01; ### Cause: java.sql.SQLSyntaxErrorException: Expression #1 of SELECT list is not in GROUP BY clause…

004——内存映射(基于鸿蒙和I.MAX6ULL)

目录 一、 ARM架构内存映射模型 1.1 页表项 1.2 一级页表映射过程 1.3 二级页表映射过程 1.4 cache 和 buffer 二、 鸿蒙内存映射代码学习 三、 为板子编写内存映射代码 3.1 内存地址范围 3.2 设备地址范围 一、 ARM架构内存映射模型 &#xff08;以前我以为页表机制…

力扣● 84.柱状图中最大的矩形

84.柱状图中最大的矩形 需要找到元素i的上一个更小的元素leftmin和下一个更小的元素rightmin&#xff0c;这样leftmin和rightmin之间的元素都比当前元素i更大&#xff0c;那么矩形的宽就是中间的这些元素&#xff1a;可以从leftmin1延伸到rightmin-1&#xff0c;长即为height[i…

阿里云轻量应用服务器和云服务器ECS有什么区别?

阿里云服务器ECS和轻量应用服务器有什么区别&#xff1f;轻量和ECS优缺点对比&#xff0c;云服务器ECS是明星级云产品&#xff0c;适合企业专业级的使用场景&#xff0c;轻量应用服务器是在ECS的基础上推出的轻量级云服务器&#xff0c;适合个人开发者单机应用访问量不高的网站…

dash 初体验(拔草)

Dash简介 Dash 是一个高效简洁的 Python 框架&#xff0c;建立在 Flask、Poltly.js 以及 React.js 的基础上&#xff0c;设计之初是为了帮助前端知识匮乏的数据分析人员&#xff0c;以纯 Python 编程的方式快速开发出交互式的数据可视化 web 应用。 搭建环境 在学习 Dash 的…

算法之美:数据结构之二叉树

平时写业务代码的时候很少写对应的算法&#xff0c;因为很少会在内存中存储大量数据&#xff0c;在需要比较大量数据的查找时&#xff0c;多会依赖的中间件&#xff0c;而中间件底层就应用了很多不同算法&#xff0c;尤其是树结构的查找存储算法&#xff0c;二分查找算法在树里…

把 Taro 项目作为一个完整分包,Taro项目里分包的样式丢失

现象&#xff1a; 当我们把 Taro 项目作为原生微信小程序一个完整分包时&#xff0c;Taro项目里分包的样式丢失&#xff0c;示意图如下&#xff1a; 原因&#xff1a; 在node_modules/tarojs/plugin-indie/dist/index.js文件里&#xff0c;限制了只有pages目录下会被引入app.w…

C# WPF编程-事件

C# WPF编程-路由事件 路由事件概要路由事件的三种方式 WPF事件WPF最重要的5类事件&#xff1a;生命周期事件 鼠标事件键盘事件多点触控输入原始触控 路由事件概要 路由事件是具有更强传播能力的事件&#xff0c;它们可在元素树中向上冒泡和向下隧道传播&#xff0c;并沿着传播…

稀碎从零算法笔记Day21-LeetCode:单词规律

题型&#xff1a;哈希表、字符串 链接&#xff1a;290. 单词规律 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 这里的 遵循 指完全匹配&#xff0c;例如&am…

uni-app从零开始快速入门

教程介绍 跨端框架uni-app作为新起之秀&#xff0c;在不到两年的时间内&#xff0c;迅速被广大开发者青睐和推崇&#xff0c;得益于它颠覆性的优势“快”&#xff0c;快到可以节省7套代码。本课程由uni-app开发者团队成员亲授&#xff0c;带领大家无障碍快速掌握完整的uni-app…

QT文件读写操作和内容提取

访问IO设备&#xff0c;需要先调用open()来设置正确的OpenMode(例如ReadOnly或ReadWrite) 打开设备后后&#xff0c;使用write() 或putChar() 写入数据到文件和设备&#xff0c;并通过调用read()&#xff0c;readLine() 或readAll() 进行读取&#xff1b;使用完设备后&#xf…

机器学习——决策树剪枝算法

机器学习——决策树剪枝算法 决策树是一种常用的机器学习模型&#xff0c;它能够根据数据特征的不同进行分类或回归。在决策树的构建过程中&#xff0c;剪枝算法是为了防止过拟合&#xff0c;提高模型的泛化能力而提出的重要技术。本篇博客将介绍剪枝处理的概念、预剪枝和后剪…

代码随想录算法训练营第二十四天| 回溯算法理论基础、LeetCode77. 组合

# 回溯算法理论基础 # Backtracking 理论基础视频讲解&#xff1a;带你学透回溯算法&#xff08;理论篇&#xff09;| 回溯法精讲&#xff01;_哔哩哔哩_bilibili #LeetCode 77. Combinations #LeetCode 77. 视频讲解&#xff1a;带你学透回溯算法-组合问题&#xff08;对应力…

力扣爆刷第103天之CodeTop100五连刷1-5

力扣爆刷第103天之CodeTop100五连刷1-5 文章目录 力扣爆刷第103天之CodeTop100五连刷1-5一、3. 无重复字符的最长子串二、206. 反转链表三、146. LRU 缓存四、215. 数组中的第K个最大元素五、25. K 个一组翻转链表 一、3. 无重复字符的最长子串 题目链接&#xff1a;https://l…