【MySQL必知会】事务

目录

🌈前言🌈

📁 事务概念

📁 事务操作

📁 事务提交方式

📁 隔离级别

📁 MVCC

 📂 3个隐藏列字段

 📂 undo日志

 📂 Read View视图

📁 RR和RC的本质区别

📁 总结


🌈前言🌈

        本期【MySQL】主要介绍MySQL中事务的概念,事务是据库管理系统中一个重要的概念,确保数据库操作可靠性的重要机制。

        本期内容主要介绍事务的概念,如何操作失误,隔离级别以及事务的底层机制。

📁 事务概念

        事务是一组DML语句,具有某种逻辑关系,完成特定操作。这些操作要么全部成功,要么全部失败,不能有其他状态。

事务四大特性:

  1. 原子性(Atomicity)

            事务中的所有操作要么全部执行成功,要么全部不执行。即使在执行过程中发生错误,系统也会回滚到事务开始之前的状态。
  2. 一致性(Consistency)

            事务必须使数据库从一个一致性状态转换到另一个一致性状态。在事务执行前后,数据库的完整性约束必须得到满足。
  3. 隔离性(Isolation)

            并发执行的事务之间是相互隔离的,一个事务的执行不应受到其他事务的影响。各个事务的中间状态对其他事务是不可见的。
  4. 持久性(Durability)

            一旦事务提交,其对数据库的修改就会永久保存,即使系统崩溃也不会丢失。

        我们来设想一下事务场景,例如抢火车票。

        当我们使用上层程序,访问数据库抢票时,我们是否需要保证过程的原子性操作,确保不会有安全问题。那么是否需要程序员来保证数据库访问的安全问题呢?事务就可以解决这个问题。

        事务的出现,简化了编程模型,不需要我们考虑各种潜在的错误和迸发问题,当我们使用事务时,事务就确保了原子性。因此,事务本质上是为了应用层服务的。

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

show engines;

📁 事务操作

1. 开启事务
begin
//start transaction2. 提交事务
commit 3. 回滚
rollback savepoint //回滚到保存点
rollback    //回滚到最开始4. 设置保存点
savepoint [保存点名字]

📁 事务提交方式

        事务提交方式分为:手动提交    自动提交

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    |  ON   |
+---------------+-------+//使用set改变提交模式
mysql> SET AUTOCOMMIT=0; #SET AUTOCOMMIT=0 禁止自动提交
Query OK, 0 rows affected (0.00 sec)

        事务的提交方式只影响单SQL语句,在MySQL的InnoDB中每一条SQL语句被封装成一个事务,自动提交。

        我们也可以进行手动提交,设置成手动提交后,执行完每一条SQL语句后,必须commit。

        我们下面通过一个例子进行讲解:

//终端A
mysql> select * from student;
+--------+--------+
| stu_id | name   |
+--------+--------+
|      1 | 张三   |
|      2 | 李四   |
|      3 | 王五   |
|      4 | 赵六   |
+--------+--------+mysql> set autocommit=0;
Query OK, 0 rows affected (0.01 sec)mysql> insert into student values (5,'田七');
Query OK, 1 row affected (0.00 sec)mysql> select * from student;
+--------+--------+
| stu_id | name   |
+--------+--------+
|      1 | 张三   |
|      2 | 李四   |
|      3 | 王五   |
|      4 | 赵六   |
|      5 | 田七   |
+--------+--------+
5 rows in set (0.00 sec)//使用ctrl + d 终止进程
//终端B
mysql> select * from student;
+--------+--------+
| stu_id | name   |
+--------+--------+
|      1 | 张三   |
|      2 | 李四   |
|      3 | 王五   |
|      4 | 赵六   |
+--------+--------+
4 rows in set (0.00 sec)

        我们可以看到关闭自动提交后,如果你没有commit,MySQL不会将数据持久化到磁盘,而是回滚到最开始,体现了事务的原子性和一致性。

        总结一下,对于设置提交方式,只会影响一条SQL语句(封装成事务),对于begin开始的事务,事务必须通过commit提交,才会持久化,与set autocommit无关。

        此外,事务可以手动回滚,选择保存点。如果操作异常,MySQL会自动回滚,只能回滚到事务的最开始。如果commit了,就不能回滚了。

        所谓的原子性,就是通过回滚保证,事务要么执行成功,成功数据保存在磁盘,进行持久化操作;要么操作失败,回滚到最开始状态。 进行保证了一致性。

        一致性是指,数据库必须从一种状态切换到另一种状态,例如事务A成功完成操作,将数据写入数据库,数据库只包含正确完成事务结果,这就是一致状态。事务B因为操作错误,未能完成,但是未完成的事务将数据修改并保存到数据库,此时数据库就是不一致状态。

        因此一致性是通过原子性来保证的。

        

📁 隔离级别

        上面介绍了原子性,一致性,现在我们来介绍隔离性。在事务中,隔离性尤为总要。

       多事务执行过程中,执行单个或多个SQLy语句,其中如果有事务更新了表,例如插入了新的记录或修改了记录,可能会影响到另一个事务。

        为了保证事务在执行过程中尽量不受影响,就有了:隔离性。

        允许事务受不同程度的影响,就有了:隔离级别。

隔离级别:

        读未提交【Read Uncommitted】: 在该隔离级别,所有的事务都可以看到其他事务没有提交的执行结果。(实际生产中不可能使用这种隔离级别的),但是相当于没有任何隔离性,也会有很多并发问题,如脏读,幻读,不可重复读等,我们上面为了做实验方便,用的就是这个隔离性。

        读提交【Read Committed】 :该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读,即一个事务执行时,如果多次 select, 可能得到不同的结果。

        可重复读【Repeatable Read】: 这是 MySQL 默认的隔离级别,它确保同一个事务,在执行中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题。

        串行化【Serializable】: 这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争(这种隔离级别太极端,实际生产基本不使用)

//查看和设置隔离性
mysql> select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| REPEATABLE-READ                |
+--------------------------------+
1 row in set (0.00 sec)mysql> select @@session.transaction_isolation;
+---------------------------------+
| @@session.transaction_isolation |
+---------------------------------+
| REPEATABLE-READ                 |
+---------------------------------+
1 row in set (0.00 sec)mysql> set global transaction isolation level  [隔离级别]mysql> set session transaction isolation level  [隔离级别]

        不可重复读,事务A查询表,事务B更新或修改表,事务A再次查表的时候,两次读取值不一样。

        幻读是指,事务A查询表,事务B插入新的记录,事务A再次查表的时候,两次读取记录数不一样。

        mysql 默认的隔离级别是可重复读,一般情况下不要修改。其中隔离级别越严格,安全性越高,但数据库的并发性能也就越低。

📁 MVCC

        上面我们了解了隔离级别,接下来我们从业务角度理解隔离级别,并且区分RR和RC的本质区别。

        通过3个隐藏字段,和undo日志,我们来了解MySQL如何做到进行看到不同版本(通过版本链),解决脏读问题。

        学习Read View,进而了解到RR和RC的本质区别,如何解决不可重复度问题。

 📂 3个隐藏列字段

        DB_TRX_ID :6 byte,最近修改( 修改/插入 )事务ID,记录创建这条记录/最后一次修改该记录的事务ID。

        DB_ROLL_PTR : 7 byte,回滚指针,指向这条记录的上一个版本(简单理解成,指向历史版本就行,这些数据一般在 undo log 中)。

        DB_ROW_ID : 6 byte,隐含的自增ID(隐藏主键),如果数据表没有主键, InnoDB 会自动以DB_ROW_ID 产生一个聚簇索引。

        补充:实际还有一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除flag变了。

 📂 undo日志

        undo log就是MySQL内存中一段内存空间,用来保存日志数据。

        MySQL以守护进程的形式,运行在内存,会在内存中开辟一段空间,所有的机制:索引,日志等都是在该内存空间中完成,即在 MySQL 内部的相关缓冲区中,保存相关数据,完成各种判断操作,在合适的时机刷新到硬盘。

        当我们执行updata等指令更新记录值时,先给该记录加锁,修改前,将该行记录拷贝到undo log中,所以undo log中就有了副本,再修改原始记录,通过回滚指针指向副本,这样就形成了版本链。

        其中MySQL中将每一条SQL语句封装成了事务,具有事务id。每一行记录都有一个隐藏列字段,其中有一列DB_TRX_ID记录被哪个事务修改。

        事务提交后,释放锁。我们就有了一个基于链表记录的历史版本链。所谓的回滚,无非就是用历史数据,覆盖当前数据
        上面的一个一个版本,我们可以称之为一个一个的快照

        上述是updata,delete就是将删除flag字段设置,因此也可以加入版本链;insert之前没有数据,可以加入版本链吗?MySQL为了回滚操作方便,因此也将insert加入版本链。

        但是select呢?select不需要对数据进行查改插入,加入版本链也没有任何意义,但是版本链对select读取非常有意义。

        在多个事务同时删改查的时候,都是当前读,是要加锁的。那同时有select过来,如果也要读取最新版(当前读),那么也就需要加锁,这就是串行化。但如果是快照读,读取历史版本的话,是不受加锁限制的。也就是可以并行执行!换言之,提高了效率,即MVCC的意义所在。

        select究竟是读取哪个版本的记录呢?这就涉及Read View和隔离级别了。

undo log清除:

  1. 事务提交:

    • 当一个事务成功提交后,该事务相关的 undo log 就可以被清除。这是因为一旦事务提交,所有的修改都是永久性的,不再需要撤销这些操作。
  2. 回滚:

    • 如果事务由于某种原因被回滚,相关的 undo log 也会被清除,因为它们不再需要保留。
  3. 空间回收:

    • 在特定情况下,InnoDB 会进行空间回收,以释放不再需要的 undo log。当系统检测到某些 undo log 不再被任何活动事务引用时,这些日志就会被清除。
  4. InnoDB 的内部机制:

    • InnoDB 会定期检查和清理未使用的 undo log,尤其是在执行 CHECKPOINT 操作时,系统会尝试清理旧的 undo log,以控制日志文件的大小并优化性能。
  5. 配置参数:

    • 用户可以通过配置参数(如 innodb_undo_logs 和 innodb_max_undo_log_size)来影响 undo log 的管理,但具体的清除行为仍然依赖于 InnoDB 的内部管理机制。

 📂 Read View视图

        Read View就是事务进行快照读操作的时候生产的读视图 (Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID(当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以最新的事务,ID值越大)

        Read View 在 MySQL 源码中,就是一个类,本质是用来进行可见性判断的。即当进行快照读的时候,创建read view进行判断,select读取现版本,还是某个历史版本。

        每次创建read view对象后,创建出来后read view不能再被修改。

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;// 省略...
};

        m_ids: 一张列表,用来维护Read View生成时刻,系统正活跃的事务ID

        up_limit_id: 记录m_ids列表中事务ID最小的ID(没有写错)

        low_limit_id: ReadView生成时刻系统尚未分配的下一个事务ID,也就是目前已出现过的事务ID的最大值+1(也没有写错)

        creator_trx_id: 创建该ReadView的事务ID

        以上就是进行快照读时,read view的作用,就是用来进行判断可视化的,该快照对哪些事务是可见的,对哪些事务是不可见的。

select * from user lock in share mode ,以加共享锁方式进行读取,对应的就是当前读。

        Read View会记录下此时其他所有活动事务的快照,这些事务的修改对于当前事务是不可见的,而早于read view创建的事务所做的修改是可见的,晚于read view创建的修改是不可见的。

📁 RR和RC的本质区别

        因为read view不可修改,因此read view的创建时机非常重要,事务A可能上一秒进行快照读,不能读取事务B更新的结果,但是下一秒就能看到。

事务A操作事务A描述事务B描述事务B操作
begin开启事务开启事务begin
select * fromuser快照读(无影响)查询快照读查询select * from user
update user setage=18 where id=1;更新age=18--
commit提交事务--
select 快照读 ,没有读到age=18select * from user
select lock in sharemode当前读 , 读到age=18select * from userlock in share mode
事务A操作事务A描述事务B描述事务B操作
begin开启事务开启事务begin
select * fromuser快照读,查到age=18--
update user setage=28 where id=1;更新age=28--
commit提交事务--
select 快照读 age=28select * from user
select lock in sharemode当前读 age=28select * from userlock in share mode

        通过上述例子,我们可以看出事务中快照读的结果是非常依赖该事务首次出现快照读的地方,即某个事务中首次出现快照读,决定该事务后续快照读结果的能力。

        正是read view生成时机不同,才造就了RC,RR级别下快照读的结果的不同。

RR 与 RC的本质区别:
      在RC隔离级别下,每次进行快照读的时候都会创建新的read view;在RR级别下,再试同一个事物的第一个快照才会创建read view,此后同一个事物的快照都采用同一个read view。

        

📁 总结

        以上,就是本期【MySQL必知会】,重点就是事务的概念,隔离级别,以及MVCC。其中,版本链,read view对事务可见性的影响,RC和RR的区别以及如何实现也是尤为重要。

        如果感觉本期内容对你有帮助,欢迎点赞,关注,收藏Thanks♪(・ω・)ノ

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

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

相关文章

【GESP】C++一级练习BCQM3028,输入-计算-浮点型格式化输出

目前的几道题主要围绕浮点型的计算和格式化输出。强化基础语法练习。 详解详见:https://www.coderli.com/gesp-1-bcqm3028/ 【GESP】C一级练习BCQM3028,输入-计算-浮点型格式化输出 | OneCoder目前的几道题主要围绕浮点型的计算和格式化输出。强化基础语…

说说BPMN概念及应用

BPMN(Business Process Modeling and Notation)即业务流程建模与标注,是一种由OMG(Object Management Group,对象管理组织)制定的业务流程建模语言。以下是对BPMN标准的详细解释: 一、BPMN的起…

短剧系统源码短剧平台开发(H5+抖小+微小)部署介绍流程

有想法加入国内短剧赛道的请停下脚步,耐心看完此篇文章,相信一定会对您有所帮助的,下面将排序划分每一个步骤,短剧源码、申请资料、服务器选择、部署上架到正常运行等几个方面,整理了一些资料,来为大家举例…

Spring Boot助力医院数据管理

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常适…

MySQL进阶学习一(2024.10.07版)

2024-10-06 -------------------------------------------------------------------------------------------------------------------------------- 1.一条SQL语句是如何执行的 单进程的多线程模型 MySQL的物理目录 show global variables like "%basedir%"; …

LSTM时序预测 | Python实现LSTM长短期记忆神经网络时间序列预测

本文内容:Python实现LSTM长短期记忆神经网络时间序列预测,使用的数据集为AirPassengers 目录 数据集简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 数据集简介 AirPassengers 数据集的来源可以追溯到经典的统计和时间序列分析文献。原始数据集由 Box,…

面向对象特性中 继承详解

目录 概念: 定义: 定义格式 继承关系和访问限定符 基类和派生类对象赋值转换: 继承中的作用域: 派生类的默认成员函数 继承与友元: 继承与静态成员: 复杂的菱形继承及菱形虚拟继承: 虚…

VGG16模型实现MNIST图像分类

MNIST图像数据集 MNIST(Modified National Institute of Standards and Technology)是一个经典的机器学习数据集,常用于训练和测试图像处理和机器学习算法,特别是在数字识别领域。该数据集包含了大约 7 万张手写数字图片&#xf…

喜讯 | 攸信技术入选第六批专精特新“小巨人”企业

日前,根据工信部评审结果,厦门市工业和信息化局公示了第六批专精特新“小巨人”企业和第三批专精特新“小巨人”复核通过企业名单,其中,厦门攸信信息技术有限公司进入第六批专精特新“小巨人”企业培育。 “专精特新”企业是指具有…

图像分割恢复方法

传统的图像分割方法主要依赖于图像的灰度值、纹理、颜色等特征,通过不同的算法将图像分割成多个区域。这些方法通常可以分为以下几类: 1.基于阈值的方法 2.基于边缘的方法 3.基于区域的方法 4.基于聚类的方法 下面详细介绍这些方法及其示例代码。 1. 基…

代码随想录--栈与队列--用栈实现队列

队列是先进先出,栈是先进后出。 如图所示: 题目 使用栈实现队列的下列操作: push(x) – 将一个元素放入队列的尾部。 pop() – 从队列首部移除元素。 peek() – 返回队列首部的元素。 empty() – 返回队列是否为空。 示例: MyQueue qu…

draw.io 设置默认字体及添加常用字体

需求描述 draw.io 是一个比较好的开源免费画图软件。但是其添加容器或者文本框时默认的字体是 Helvetica,一般的期刊、会议论文或者学位论文要求的英文字体是 Times New Roman,中文字体是 宋体,所以一般需要在文本字体选项里的下拉列表选择 …

分层解耦-05.IOCDI-DI详解

一.依赖注入的注解 在我们的项目中,EmpService的实现类有两个,分别是EmpServiceA和EmpServiceB。这两个实现类都加上Service注解。我们运行程序,就会报错。 这是因为我们依赖注入的注解Autowired默认是按照类型来寻找bean对象的进行依赖注入…

2-115 基于matlab的瞬态提取变换(TET)时频分析

基于matlab的瞬态提取变换(TET)时频分析,瞬态提取变换是一种比较新的TFA方法。该方法的分辨率较高,能够较好地提取出故障的瞬态特征,用于故障诊断领域。通过对原始振动信号设置不同信噪比噪声,对该方法的抗…

关于一个模仿qq通信程序

7月份的时候还在学校那个时候想要学习嵌入式Linux,但是还没有买开发板来玩,再学linux系统编程,网络编程,Linux系统的文件IO,于是学完之后想做一个模仿qq的通信程序于是就有了这个“ailun.exe”,因为暑假去打…

【数据结构与算法】线性表

文章目录 一.什么是线性表?二.线性表如何存储?三.线性表的类型 我们知道从应用中抽象出共性的逻辑结构和基本操作就是抽象数据类型,然后实现其存储结构和基本操作。下面我们依然按这个思路来认识线性表 一.什么是线性表? 定义 线性…

TryHackMe 第7天 | Web Fundamentals (二)

继续介绍一些 Web hacking 相关的漏洞。 IDOR IDOR (Insecure direct object reference),不安全的对象直接引用,这是一种访问控制漏洞。 当 Web 服务器接收到用户提供的输入来检索对象时 (包括文件、数据、文档),如果对用户输入数据过于信…

【springboot】使用代码生成器快速开发

接上一项目&#xff0c;使用mybatis-plus-generator实现简易代码文件生成 在fast-demo-web模块中的pom.xml中添加mybatis-plus-generator、freemarker和Lombok依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator&…

Python | 由高程计算坡度和坡向

写在前面 之前参加一个比赛&#xff0c;提供了中国的高程数据&#xff0c;可以基于该数据进一步计算坡度和坡向进行相关分析。 对于坡度和坡向&#xff0c;这里分享一个找到的库&#xff0c;可以方便快捷的计算。这个库为&#xff1a;RichDEM&#xff0c;官网地址如下 https…

SAP学习笔记 - 豆知识11 - 如何查询某个字段/DataElement/Domain在哪个表里使用?

大家知道SAP的表有10几万个&#xff08;也有说30多万个的&#xff0c;总之很多就是了&#xff09;&#xff0c;而且不断增多&#xff0c;那么当想知道一个字段在哪个表里使用的时候该怎么办呢&#xff1f; 思路就是SAP的表其实也是存在表里的&#xff1a;&#xff09;&#xf…