深入理解MySQL事务(万字详)

文章目录

  • 什么是事务
  • 为什么会出现事务
  • 事务的版本支持
  • 事务的提交方式
  • 事务常见操作方式
    • 正常演示 - 证明事务的开始与回滚
    • 非正常演示1 - 证明未commit,客户端崩溃,MySQL自动会回滚(隔离级别设置为读未提交)
    • 非正常演示2 - 证明commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化
    • 非正常演示3 - 对比试验。begin会自动更改提交方式
    • 非正常演示4 - 证明单条 SQL 与事务的关系
  • 事务的隔离级别
    • 查看与设置隔离性
    • 读未提交(Read Uncommitted)
    • 读提交(Read Committed)
    • 可重复读(Repeatable Read)
    • 串行化(Serializable)
    • 一致性
  • 多版本并发控制MVCC
    • 3个记录隐藏列字段
    • undo日志
    • 快照
    • Read View

什么是事务

首先,我们知道MySQL是一定会在同时被多个用户访问的,那么就会发送下面这种情况

在这里插入图片描述
上述情况就会导致,同一张票被出售两次,显然不合理;

那么我们应该如何做,才可以避免上述情况呢?当满足下列条件时,即可避免

  • 买票的过程是原子的

我买票的时候别人不能影响我

  • 买票的过程不能互相影响

我正在买的时候,你来买了

  • 买完票应该是永久的

我买完票,交完钱了,你不能不给我票,直接扣我的钱,而什么也不给我,即不给票也不还钱

  • 买前,买后状态是确定的

买前、买后、买成功、买失败,不能模棱两可,一定是确定的,成不成功并不重要

那么到底什么是事务呢???

事务是一组逻辑上相关的数据库操作(DML语句),这些操作要么全部成功,要么全部失败。事务的主要目的是确保数据的完整性和一致性。例如,在一个银行转账系统中,转账操作需要同时更新两个账户的余额,这两个操作必须作为一个整体执行,否则会导致数据不一致。

  • 我对我的账号+100
  • 我对你的账号-100

单独的一条SQL并没有实际意义

一个 MySQL 数据库,可不止你一个事务在运行,同一时刻,甚至有大量的请求被包
装成事务,在向 MySQL 服务器发起事务处理请求。而每条事务至少一条 SQL ,最多很多 SQL ,这样如果大家都访问同样的表数据,在不加保护的情况,就绝对会出现问题

所以,一个完整的事务,绝对不是简单的 sql 集合,还需要满足如下四个属性,通常称为ACID属性:

  • 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败。如果事务在执行过程中发生错误,系统会回滚到事务开始前的状态

  • 一致性(Consistency):事务执行前后,数据库必须保持一致状态。这意味着事务执行后,数据库必须满足所有的完整性约束

  • 隔离性(Isolation):多个事务并发执行时,每个事务的操作应该与其他事务隔离,防止数据不一致。MySQL提供了不同的隔离级别来控制事务的隔离程度,包括读未提交( Readuncommitted )、读提交( read committed )、可重复读( repeatable read )和串行化( Serializable )

  • 持久性(Durability):一旦事务提交,对数据的修改就是永久的,即使系统发生故障也不会丢失

综上,事务就是在ACID四大属性的加持下,由一条、多条SQL构成的;
事务的本质(白话)是站在MySQL使用者角度,我要完成一个功能(转账),这个功能由多条SQL语句组成;

为什么会出现事务

首先,事务被 MySQL 编写者设计出来;
本质是为了当应用程序访问数据库的时候,事务能够简化我们的编程模型,
不需要我们去考虑各种各样的潜在错误和并发问题。
因此事务本质上是为了应用层服务的,而不是伴随着数据库系统天生就有的。

事务的版本支持

首先,在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务, MyISAM 不支持。

我们可以通过以下SQL来查询
在这里插入图片描述

  • Engine: 表示存储引擎的名称
  • Support: 表示服务器对存储引擎的支持级别,YES表示支持,NO表示不支持,DEFAULT表示数据库默认使用的存储引擎,DISABLED表示支持引擎但已将其禁用
  • Comment: 表示存储引擎的简要说明
  • Transactions: 表示存储引擎是否支持事务,可以看到InnoDB存储引擎支持事务,而MyISAM存储引擎不支持事务
  • XA: 表示存储引擎是否支持XA事务
  • Savepoints: 表示存储引擎是否支持保存点

事务的提交方式

事务的提交方式常见的有两种:

  • 自动提交
  • 手动提交

我们可以用下面SQL来查询当前的提交方式

在这里插入图片描述
此时Value的值为ON表示自动提交

用 SET 来改变 MySQL 的自动提交模式:

在这里插入图片描述
将autocommit的值设置为1表示打开自动提交,设置为0表示关闭自动提交

事务常见操作方式

正常演示 - 证明事务的开始与回滚

提前准备

为了便于演示,我们将MySQL的隔离级别设置的比较低,即成读未提交
在这里插入图片描述
现象如下
在这里插入图片描述

创建测试表,简单银行用户表

在这里插入图片描述

启动一个事务,一旦启动后,之后的所有SQL都属于同一个事务

两种启动事务的方式

在这里插入图片描述

设置savapoint s1并插入一条数据

在这里插入图片描述
在这里插入图片描述
设置savapoint s2并插入一条数据
在这里插入图片描述

在这里插入图片描述

设置savapoint s3并插入一条数据
在这里插入图片描述
在这里插入图片描述

回滚事务

回滚到s3时,s3后面的SQL就没有了;
回滚到s1时,s1后面的SQL就没有了;

在这里插入图片描述在这里插入图片描述

提交事务

提交事务后就不能回滚了

在这里插入图片描述

丢弃整个SQL,直接rollback;

在这里插入图片描述

非正常演示1 - 证明未commit,客户端崩溃,MySQL自动会回滚(隔离级别设置为读未提交)

在这里插入图片描述
事务在提交之前因为某些原因与MySQL断开连接,那么MySQL会自动让事务回滚到最开始,此时事务内容无效;
这也就是ACID中的A属性,原子性

非正常演示2 - 证明commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化

在这里插入图片描述

非正常演示3 - 对比试验。begin会自动更改提交方式

查看autocommit的值为ON,表示事务的提交方式是自动提交

在这里插入图片描述

事务在提交之前与MySQL断开连接,那么MySQL依旧会自动让事务回滚到最开始;

证明begin操作会自动更改提交方式,不会受MySQL是否自动提交影响

非正常演示4 - 证明单条 SQL 与事务的关系

将autocommit设置为ON,表示事务执行后自动提交

在这里插入图片描述

  • 查看autocommit的值为ON,表示事务的提交方式是自动提交
  • 左终端中直接向表中新插入一条记录,由于隔离级别是读未提交,因此在右终端中肯定能够查询到新插入的这条记录
  • 执行单条SQL后不使用commit进行提交,MySQL异常退出,这时右终端仍然可以看到之前新插入的记录了,因为单条SQL在执行后被自动提交持久化了

将autocommit设置为OFF,表示事务执行后需要手动提交

在这里插入图片描述

  • 设置autocommit的值为OFF,表示事务执行后需要手动提交
  • 左终端中直接向表中新插入一条记录,由于隔离级别是读未提交,因此在右终端中肯定能够查询到新插入的这条记录
  • 执行单条SQL后不使用commit进行提交,MySQL异常退出,这时右终端看不到之前新插入的记录了,因为单条SQL在执行后异常退出,MySQL断开连接则会自动进行回滚操作

结论:我们之前一直都在使用单SQL事务,只不过autocommit默认是打开的,因此单SQL事务执行后自动就被提交了

事务的隔离级别

举个例子:

你妈妈给你说:你要么别学,要学就学到最好。至于你怎么学,中间有什么困难,你妈妈不关心。那么你的学习,对你妈妈来讲,就是原子的。那么你学习过程中,很容易受别人干扰,此时,就需要将你的学习隔离开,保证你的学习环境是健康的。

  • 数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性
  • 数据库中,允许事务受不同程度的干扰,就有了一种重要特征:隔离级别

隔离级别

  • 读未提交(Read Uncommitted):事务可以读取其他事务未提交的数据,可能会导致脏读、不可重复读和幻读。

  • 读已提交(Read Committed):事务只能读取其他事务已提交的数据,避免了脏读,但可能会导致不可重复读和幻读。

  • 可重复读(Repeatable Read):MySQL默认的隔离级别,确保同一事务中多次读取同一数据时,结果一致。避免了脏读和不可重复读,但可能会有幻读。

  • 串行化(Serializable):最高的隔离级别,强制事务串行执行,避免了脏读、不可重复读和幻读,但性能最差。

查看与设置隔离性

查看隔离级别

  • 查看全局的隔离级别
SELECT @@global.transaction_isolation;

在这里插入图片描述

  • 查看会话隔离级别
SELECT @@session.transaction_isolation;

在这里插入图片描述
也可以省略掉session

SELECT @@transaction_isolation;

在这里插入图片描述

设置隔离级别

语法:

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED 
| READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
  • 设置会话隔离级别

在这里插入图片描述
只会影响当前会话的隔离级别,不会影响全局的,即使新起会话也不会影响

  • 设置全局隔离级别

在这里插入图片描述

设置全局隔离级别会影响后续的新会话,但当前会话的隔离级别没有发生变化,如果要让当前会话的隔离级别也改变,则需要重启会话

读未提交(Read Uncommitted)

事务A所作的修改在没有提交之前,事务B就已经能够看到了

在这里插入图片描述
一个事务在执行中,读到另一个执行中事务的更新(或其他操作)但是未commit的数据,这种现象叫做脏读

读提交(Read Committed)

事务A所作的修改在没有提交之前,事务B不能看到
只有当事务A提交后,事务B才能看到修改后的数据
在这里插入图片描述
在B事务没有commit之前,执行过程中,两个相同的select查询得到了不同的数据,这种现象叫做不可重复读

不可重复读是个问题吗??

可重复读(Repeatable Read)

A事务修改数据,B事务并不能查到
在这里插入图片描述
只有A事务commit后,B事务也查不到
在这里插入图片描述
只有当双方都commit后,B事务才可以查到
在这里插入图片描述

  • 在可重复读隔离级别下,一个事务在执行过程中,相同的select查询得到的是相同的数据,这就是可重复读
  • 一个事务在执行过程中,相同的select查询得到了新的数据,如同出现了幻觉,这种现象叫做幻读

串行化(Serializable)

将隔离级别都设置为串行化,双方查询互不影响
在这里插入图片描述
此时事务A要删除一个数据,但是阻塞在了这里
在这里插入图片描述
但是事务B的查询并不受影响
在这里插入图片描述
当事务Bcommit后,离开事务A就恢复,立马执行SQL对表进行修改
在这里插入图片描述

  • 串行化是事务的最高隔离级别,多个事务同时进行读操作时加的是共享锁,因此可以并发执行读操作,但一旦需要进行写操作,就会进行串行化,效率很低,几乎不会使用

结论:

在这里插入图片描述

一致性

多版本并发控制MVCC

数据库的并发场景

  • 读-读并发:不存在任何问题,也不需要并发控
  • 读-写并发:有线程安全问题,可能会存在事务隔离性问题,可能遇到脏读、幻读、不可重复读
  • 写-写并发:有线程安全问题,可能会存在两类更新丢失问题
  1. 每个事务都有自己的事务ID,ID的大小决定着,事务到来的顺序;
  2. mysqld可能会在一个时间范围中处理多个事务,事务也有自己的声明周期,mysqld要对多个事务进行管理;

3个记录隐藏列字段

在这里插入图片描述

当我们创建下面一个表
在这里插入图片描述
该记录不仅包含name和age字段,还包含上述三个隐藏字段

undo日志

MySQL 中的一段内存缓冲区,用来保存日志数据的

  • redo log:重做日志,用于MySQL崩溃后进行数据恢复,保证数据的持久性
  • bin log:逻辑日志,用于主从数据备份时进行数据同步,保证数据的一致性
  • undo log:回滚日志,用于对已经执行的操作进行回滚,保证事务的原子性

快照

现在有一个事务ID为10的事务,要将刚才插入学生表中的记录的学生姓名“张三”改为“李四”

  • 事务10,因为要修改,所以要先给该记录加行锁
  • 修改前,现将改行记录拷贝到undo log中,所以,undo log中就有了一行副本数据。(原理就是写时拷贝)
  • 所以现在 MySQL 中有两行同样的记录。现在修改原始记录中的name,改成 ‘李四’。并且修改原始记录的隐藏字段 DB_TRX_ID 为当前 事务10 的ID, 我们默认从 10 开始,之后递增。而原始记录的回滚指针 DB_ROLL_PTR列,里面写入undo log中副本数据的地址,从而指向副本记录,既表示我的上一个版本就是它
  • 事务10提交,释放锁

在这里插入图片描述

又有一个事务11,对student表中记录进行修改(update):将age(28)改成age(38)

  • 先给该记录加行锁
  • 修改前,现将改行记录拷贝到undo log中,所以,undo log中就又有了一行副本数据。此时,新的副本,我们采用头插方式,插入undo log
  • 现在修改原始记录中的age,改成 38。并且修改原始记录的隐藏字段 DB_TRX_ID 为当前 事务11 的ID。而原始记录的回滚指针 DB_ROLL_PTR 列,里面写入undo log中副本数据的地址,从而指向副本记录,既表示我的上一个版本就是它
  • 事务11提交,释放锁

在这里插入图片描述
这样就形成了一个基于历史版本的链表

上面的每个版本,我们可以称之为快照

当前读 、快照读

当前读:读取最新的记录,就叫做当前读。
快照读:读取历史版本,就叫做快照读。

事务在进行增删查改的时候,并不是都需要进行加锁保护:

  • 事务对数据进行增删改的时候,操作的都是最新记录,即当前读,需要进行加锁保护

  • 事务在进行select查询的时候,既可能是当前读也可能是快照读,如果是当前读,那也需要进行加锁保护,但如果是快照读,那就不需要加锁,因为历史版本不会被修改,也就是可以并发执行,提高了效率,这也就是MVCC的意义

Read View

Read View就是事务进行 快照读 操作的时候生产的读视图 (Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID

其源码

class ReadView {// 省略...
private:/** 高水位:大于等于这个ID的事务均不可见*/trx_id_t m_low_limit_id;/** 低水位:小于这个ID的事务均可见 */trx_id_t m_up_limit_id;/** 创建该 Read View 的事务ID*/trx_id_t m_creator_trx_id;/** 创建视图时的活跃事务id列表*/ids_t m_ids;/** 配合purge,标识该视图不需要小于m_low_limit_no的UNDO LOG,* 如果其他视图也不需要,则可以删除小于m_low_limit_no的UNDO LOG*/trx_id_t m_low_limit_no;/** 标记视图是否被关闭*/bool m_closed;// 省略...
};

在这里插入图片描述
也就是

  • id < m_up_limit_id || id == m_creator_trx_id
    事务id小于m_up_limit_id(已提交)或事务id为创建该Read View的事务的id,则可见

  • id >= m_low_limit_id
    事务id大于等于m_low_limit_id,则不可见

  • m_ids.empty()
    事务id位于m_up_limit_id和m_low_limit_id之间,并且活跃事务id列表为空(即不在活跃列表中),则可见

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

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

相关文章

[Spring] Gateway详解

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

Arduino Uno 和 1.44 英寸 TFT 屏幕(SPI 接口)初体验

在嵌入式项目中&#xff0c;1.44 英寸 TFT 屏幕&#xff08;SPI 接口&#xff09;是一种非常实用的显示设备&#xff0c;适合用于显示文本、图形和简单动画。本文将详细介绍如何使用 Arduino Uno 和 1.44 英寸 TFT 屏幕进行基本的显示操作&#xff0c;包括显示文本、绘制图形和…

Linux应用编程(五)USB应用开发-libusb库

一、基础知识 1. USB接口是什么&#xff1f; USB接口&#xff08;Universal Serial Bus&#xff09;是一种通用串行总线&#xff0c;广泛使用的接口标准&#xff0c;主要用于连接计算机与外围设备&#xff08;如键盘、鼠标、打印机、存储设备等&#xff09;之间的数据传输和电…

Git处理冲突详解

文章目录 Git处理冲突详解一、引言二、冲突产生的原因三、解决冲突的步骤1. 手动解决冲突1.1 查看冲突文件1.2 编辑冲突文件1.3 提交解决冲突 2. 使用合并工具解决冲突 四、使用示例五、总结 Git处理冲突详解 一、引言 在团队协作开发中&#xff0c;Git冲突是不可避免的。当多…

Linux 下注册分析(4)

系列文章目录 Linux 设备树 Linux 下注册分析&#xff08;1&#xff09; Linux 下注册分析&#xff08;2&#xff09; Linux 下注册分析&#xff08;3&#xff09; Linux 下注册分析&#xff08;4&#xff09; 文章目录 系列文章目录1、device_create简介device_createdevice_c…

第十五届蓝桥杯大赛软件赛省赛Java 大学 B 组(1、2题)

1.报数游戏 问题描述 小蓝和朋友们在玩一个报数游戏。由于今年是 2024 年&#xff0c;他们决定要从小到大轮流报出是 20或 24 倍数的正整数。前 10 个被报出的数是&#xff1a;20,24,40,48,60,72,80,96,100,120。请问第 202420242024个被报出的数是多少? 答案提交 这是一道结果…

批量修改图片资源的属性。

Unity版本2022.3 如图&#xff0c;比如我们想要修改图片的属性的时候&#xff0c;大部分都是 TextureImporter importer (TextureImporter)AssetImporter.GetAtPath("Assets/1.png"); // 获取文件 importer.xxxxxxx xxxxxxx; // 修改属性到这里没什么问题&#xf…

基于神经网络的视频编码NNVC(1):帧内预测

在H.266/VVC发布后&#xff0c;基于传统编码框架提升压缩率越来越难&#xff0c;随着深度学习的发展&#xff0c;研究人员开始尝试将神经网络引入编码器。为此&#xff0c;JVET工作组在2020年成立AHG11小组来专门进行基于神经网络的视频编码的研究。 为了方便研究&#xff0c;工…

C语言初阶牛客网刷题—— HJ97 记负均正【难度:简单】

1. 题目描述 牛客网在线OJ题 1、首先输入要输入的整数个数 n &#xff0c;然后输入 n 个整数。输出为 n 个整数中负数的个数&#xff0c;和所有正整数的平均值&#xff0c; 结果保留一位小数。 注意&#xff1a; 0 即不是正整数&#xff0c;也不是负数&#xff0c;不计入计算&…

【Web开发】一步一步详细分析使用Bolt.new生成的简单的VUE项目

https://bolt.new/ 这是一个bolt.new生成的Vue小项目&#xff0c;让我们来一步一步了解其架构&#xff0c;学习Vue开发&#xff0c;并美化它。 框架: Vue 3: 用于构建用户界面。 TypeScript: 提供类型安全和更好的开发体验。 Vite: 用于快速构建和开发 主界面如下&#xff1a…

Rabbitmq高级特性之消费方确认

背景&#xff1a; 发送方发送消息之后&#xff0c;到达消费端之后&#xff0c;可能会有以下情况&#xff1a;消息处理成功&#xff0c;消息处理异常。RabbitMQ在向消费者发送消息之后&#xff0c;就会把这条消息给删除掉&#xff0c;那么第二种情况&#xff0c;就会造成消息丢…

基于微信小程序的健身管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

Couchbase UI: Server

在 Couchbase UI 中的 Server&#xff08;服务器&#xff09;标签页主要用于管理和监控集群中的各个节点。以下是 Server 标签页的主要内容和功能介绍&#xff1a; 1. 节点列表 显示集群中所有节点的列表&#xff0c;每个节点的详细信息包括&#xff1a; 节点地址&#xff1…

Spark Streaming编程基础

文章目录 1. 流式词频统计1.1 Spark Streaming编程步骤1.2 流式词频统计项目1.2.1 创建项目1.2.2 添加项目依赖1.2.3 修改源目录1.2.4 添加scala-sdk库1.2.5 创建日志属性文件 1.3 创建词频统计对象1.4 利用nc发送数据1.5 启动应用&#xff0c;查看结果 2. 编程模型的基本概念3…

OpenCV imread函数读取图像__实例详解

OpenCV imread函数读取图像__实例详解 本文目录&#xff1a; 零、时光宝盒 一、imread函数定义 二、imread函数支持的文件格式 三、imread函数flags参数详解 &#xff08;3.1&#xff09;、Flags-1时&#xff0c;样返回加载的图像&#xff08;使用alpha通道&#xff0c;否…

ssm基于HTML5的红酒信息分享系统

SSM基于HTML5的红酒信息分享系统是一个专注于红酒领域的综合性信息平台&#xff0c;旨在为红酒爱好者、从业者以及普通消费者提供一个便捷的交流与获取红酒相关信息的空间。 一、系统背景与意义 随着人们生活水平的提高和消费观念的转变&#xff0c;红酒作为一种高雅的饮品&a…

Windows Docker Desktop安装及使用 Docker 运行 MySQL

Docker Desktop是Docker的官方桌面版&#xff0c;专为Mac和Windows用户设计&#xff0c;提供了一个简单易用的界面来管理和运行Docker容器。它集成了Docker引擎&#xff0c;为开发人员提供了一个快速、可靠、可扩展的方式来构建、运行和管理应用。DockerDesktop的优势在于&…

人形机器人,自动驾驶“老炮”创业第二站

造一台人形机器人&#xff0c;或许正在成为2025年最炙手可热的事情。 从去年第四季度开始&#xff0c;伴随着大模型应用的深入&#xff0c;具身智能概念被点燃&#xff0c;其中最鲜明的一个特点是&#xff0c;大量自动驾驶大佬的转行加入。 随便说几个比较有分量的&#xff0…

Flutter_学习记录_基本组件的使用记录

1.TextWidge的常用属性 1.1TextAlign: 文本对齐属性 常用的样式有&#xff1a; TextAlign.center 居中TextAlign.left 左对齐TextAlign.right 有对齐 使用案例&#xff1a; body: Center(child: Text(开启 TextWidget 的旅程吧&#xff0c;珠珠, 开启 TextWidget 的旅程吧&a…

什么是COLLATE排序规则?

在当今数字化世界中&#xff0c;数据的整理、比较和排序是至关重要的。在数据库管理和编程语言中&#xff0c;我们经常需要对字符串进行排序&#xff0c;以展示或处理信息。为了实现这一点&#xff0c;各种系统和工具提供了排序规则&#xff0c;其中COLLATE排序规则就是其中的一…