【MySQL】深入解析事务与MVCC

news2024/10/1 7:45:59

文章目录

      • 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,在事务操作期间其他事务提交记录也能够读取到。

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

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

相关文章

『K8S 入门』三:资源调度

『K8S 入门』三&#xff1a;资源调度 一、Label 和 Selector 可以通过 Selector 基于 Label 匹配需要的资源 Label 标签 配置文件中&#xff08;metadata.labels&#xff09;配置 metadata: # Pod相关的元数据&#xff0c;用于描述Pod的数据name: nginx-demo #Pod的名称lab…

阅读笔记(ICIP2023)Rectangular-Output Image Stitching

“矩形输出”图像拼接 Zhou, H., Zhu, Y., Lv, X., Liu, Q., & Zhang, S. (2023, October). Rectangular-Output Image Stitching. In 2023 IEEE International Conference on Image Processing (ICIP) (pp. 2800-2804). IEEE. 0. 摘要 图像拼接的目的是将两幅视场重叠的…

GDC期间LayaAir启动全球化战略

3 月 18 日至 3 月 22 日&#xff0c;一年一度的游戏开发者大会&#xff08;GDC&#xff09;在美国旧金山举行。在此期间&#xff0c;Layabox宣布LayaAir引擎启动全球扩张战略&#xff0c;这标志着引擎将步入快速发展的新阶段。此举旨在利用公司先进的3D引擎技术&#xff0c;将…

力扣每日一题 2024/3/23 统计桌面上的不同数字

题目描述 用例说明 思路讲解 给定整数n&#xff0c;找出循环十亿天后桌上的数字。可以先通过一天来找找规律。 第一天 n%i1 &#xff08;1<i<n&#xff09;只有n-1符合.加入桌面 第二天(n-1)%i1 &#xff08;1<i<n-1&#xff09;只有n-2符合 加入桌面 依次类推…

RHEL9部署Docker环境

华子目录 Docker引擎架构docker引擎架构示意图执行过程示例 RHEL9上安装Docker1.系统要求2.安装yum-utils工具包3.yum安装docker-ce4.配置docker镜像加速docker拉取镜像的过程配置阿里云镜像仓库重新加载守护进程重启Docker服务 5.拉取并运行hello-world镜像6.测试是否安装成功…

【LabVIEW FPGA入门】FPGA 存储器(Memory)

可以使用内存项将数据存储在FPGA块内存中。内存项以2kb为倍数引用FPGA目标上的块内存。每个内存项引用一个单独的地址或地址块&#xff0c;您可以使用内存项访问FPGA上的所有可用内存。如果需要随机访问存储的数据&#xff0c;请使用内存项。 内存项不消耗FPGA上的逻辑资源&…

stm32平衡车

目录 一.所需材料 二.PID算法&#xff08;简单说明&#xff09; 直立环 速度环 串级PID 三.使用到的外设 1.定时器输出比较-PWM 2.定时器编码器模式 3.编码器读取速度 4.电机驱动函数 5.外部中断 四、小车 调试 一.所需材料 1.陀螺仪MPU6050--读取三轴的加速度…

C++类和对象进阶

CSDN成就一亿技术人 C类的6个默认成员函数(构造)-CSDN博客https://blog.csdn.net/lh11223326/article/details/136917667?spm1001.2014.3001.5502 目录 一.再谈构造函数 1.构造函数体赋值&#xff1a; 在创建对象时&am…

# Maven Bom 的使用

Maven Bom 的使用 文章目录 Maven Bom 的使用概述BOM特点优点缺点 MavenMaven 安装安装步骤settingx.ml常用仓库地址Idea 使用maven常见坑 SpringBoot 项目Bom使用案例项目结构主项目 zerocode-back-servezc-dependency&#xff08;第三方jar管理&#xff09;子模块zc-serve子模…

Qt creator构建DLL库

文章目录 一、构建DLL库二、隐式调用DLL库 一、构建DLL库 Qt creator创建DLL项目。 实现功能函数。 运行代码&#xff0c;debug目录下会有.dll和.lib文件。 二、隐式调用DLL库 QT新建控制台项目。将.lib文件和与之关联的头文件赋值到项目文件夹。 3. 添加头文件和外部依赖库…

目标检测——YOLOR算法解读

论文&#xff1a;YOLOR-You Only Learn One Representation: Unifified Network for Multiple Tasks 作者&#xff1a;Chien-Yao Wang, I-Hau Yeh, Hong-Yuan Mark Liao 链接&#xff1a;https://arxiv.org/abs/2105.04206 代码&#xff1a;https://github.com/WongKinYiu/yolo…

Python界面库Flet(1)介绍和快速使用

Python界面库Flet(1)快速上手使用 Author&#xff1a;Once Day Date&#xff1a;2024年3月19日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: Pyt…

利用sealos安装k8s集群

1. 环境准备 准备三台干净&#xff08;未安装过k8s环境&#xff09;的虚拟机 # 所有的主机都要配置主机名和域名映射 # 设置主机名 hostnamectl set-hostname k8s-master01 # vim /etc/hosts 192.168.59.201 k8s-master01 192.168.59.202 k8s-worker01 192.168.59.203 k8…

飞鸟写作能用吗 #笔记#笔记

飞鸟写作是一个强大的论文写作工具&#xff0c;不仅可以帮助用户高效、准确地完成论文写作&#xff0c;还能帮助用户对论文进行查重和降重。那么&#xff0c;飞鸟写作能用吗&#xff1f;答案是肯定的&#xff0c;飞鸟写作非常好用&#xff01; 首先&#xff0c;飞鸟写作拥有强大…

视频记录历史播放位置效果

简介 每次打开页面视频从上一次的播放位置开始播放 利用lodash库做节流 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-sca…

MySQL | 视图

视图是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。视图的数据变化会影响到基表&#xff0c;基表的数据变化也会影响到视图。 1. 基本使用 1.1. 创建视图 create view 视图名 as select语句&#xff1b; 创建测…

自动驾驶轨迹规划之时空语义走廊(一)

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 目录 1.摘要 2.系统架构 3.MPDM 4.时空语义走廊 ​4.1 种子生成 4.2 具有语义边界的cube inflation ​4.3 立方体松弛 本文解析了丁文超老师…

JetBrains数据库驱动下载失败解决方法

本方法可通用于解决PyCharm等JetBrains家的IDE下载数据库驱动问题。 在Jet家IDE内连接数据库时&#xff0c;mysql、sqlite等的驱动有部分在 https://download.jetbrains.com 网站上&#xff0c;可能由于网络问题无法访问。 解决方法是修改 JetBrains 路径下的 jdbc.drivers.xm…

计算机基础系列 —— 从 Nand 门、DFF 到 RAM

Memory: The faculty of the brain by which data or information is encoded, stored, and retrieved when needed.It is the retention of information over time for the purpose of influencing future action —— Wikipedia 文中提到的所有实现都可以参考&#xff1a;nan…

Typecho如何去掉/隐藏index.php

Typecho后台设置永久链接后&#xff0c;会在域名后加上index.php&#xff0c;很多人都接受不了。例如如下网址&#xff1a;https://www.jichun29.cn/index.php/archives/37/&#xff0c;但我们希望最终的形式是这样&#xff1a;https://www.jichun29.cn/archives/37.html。那么…