【MySQL必知会】事务

news2024/11/25 21:39:19

目录

🌈前言🌈

📁 事务概念

📁 事务操作

📁 事务提交方式

📁 隔离级别

📁 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 transaction

2. 提交事务
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.coloradmin.cn/o/2195144.html

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

相关文章

分治算法(5)_归并排序_排序数组

个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 分治算法(5)_归并排序_排序数组 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记,欢迎大家在评论区交流讨论💌 目录 …

JavaSE——面向对象11:内部类(局部内部类、匿名内部类、成员内部类、静态内部类)

目录 一、内部类基本介绍 (一)内部类定义 (二)内部类基本语法 (三)内部类代码示例 (四)内部类的分类 二、局部内部类 三、匿名内部类(重要) (一)基本介绍 (二)基于接口的匿名内部类 (三)基于类的匿名内部类 (四)注意事项与使用细节 (五)匿名内部类的最佳实践——当…

leetcode-42. 接雨水 单调栈

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表…

Chrome浏览器调用ActiveX控件--allWebOffice控件

背景 allWebOffice控件能够实现在浏览器窗口中在线操作文档的应用(阅读、编辑、保存等),支持编辑文档时保留修改痕迹,支持书签位置内容动态填充,支持公文套红,支持文档保护控制等诸多办公功能,本…

vim编辑器安装,并修改配置使其默认显示行数

centOS默认是未安装vim编辑器的,而vim编辑器相比vi编辑器更易用一些,如需使用vim编辑器,需要进行安装。 1.需要先配置本地yum源,参见如下链接: 点击查看如何配置本地yum源 2.安装vim编辑器,并修改配置。…

滑动窗口_找出字符串中所有字母异位词、串联所有单词的子串_C++

滑动窗口_找出字符串中所有字母异位词、串联所有单词的子串_C 1. 题目解析2. 算法分析3. 代码实现4. 举一反三:串联所有单词的子串 1. 题目解析 leetcode链接:https://leetcode.cn/problems/VabMRr/ 给定两个字符串 s 和 p,找到 s 中所有 p …

helm 测试安装redis

helm search repo redis # 搜索redis的chart helm show readme bitnami/redis # 展示安装相关文档(readme文件) 拉取指定版本的安装包(chart) helm pull bitnami/redis --version 17.4.3 解压安装包 tar -xf redis-17.4.3.tgz …

Vue3 动态路由实现的一种方法

动态路由 目的: 根据服务器传回来的数据动态的注册路由信息,登录用户的角色不同生成的菜单不同 使用插件做动态路由的好处: 路由页面增加或者减少时,只需要增加或减少相关的路由文件,不需要再修改代码 服务器返回的信…

POI数据的处理与分析

POI概念 POI(Point of Interest,兴趣点)数据指的是地理空间数据中的一类,表示某一具体地点或位置的信息。通常,这些数据包含位置坐标(经纬度)、名称、地址、类别和其他相关信息。POI 数据广泛应…

毕业设计 深度学习水果识别

文章目录 1 前言2 开发简介3 识别原理3.1 传统图像识别原理3.2 深度学习水果识别 4 数据集5 部分关键代码5.1 处理训练集的数据结构5.2 模型网络结构5.3 训练模型 6 识别效果 1 前言 Hi,大家好,这里是丹成学长,今天做一个 基于深度学习的水果…

算法剖析:双指针

文章目录 双指针算法一、 移动零1. 题目2. 算法思想3. 代码实现 二、 复写零1. 题目2. 算法思想3. 代码实现 三、 快乐数1. 题目2. 算法思想3. 代码实现 四、 盛水最多的容器1. 题目2. 算法思想3. 代码实现 五、有效三角形的个数1. 题目2. 算法思想3. 代码实现 六、 和为 s 的两…

【EXCEL数据处理】000020 案例 保姆级教程,附多个操作案例。EXCEL使用表格。

前言:哈喽,大家好,今天给大家分享一篇文章!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【EXCEL数据处理】000020 案例 保姆级教程,附多个操作案例。…

【强训笔记】day27

NO.1 代码实现&#xff1a; #include<iostream>using namespace std;int n,m; int main() {cin>>n>>m;long long retn;for(int i0;i<m-1;i)retret*(n-1)%109;cout<<ret<<endl;return 0; }NO.2 思路&#xff1a;bfs遍历实现&#xff0c;dis…

Android架构--MVVM

一、开发架构 是什么&#xff1f; 二、Android开发中的架构 具体到Android开发中&#xff0c;开发架构就是描述 视图层、逻辑层、数据层 三者之间的关系和实施&#xff1a; 视图层&#xff1a;用户界面&#xff0c;即界面的展示、以及交互事件的响应。 逻辑层&#xff1a;为…

IL2CPP和Mono的区别

Mono 是一种开源的跨平台 .NET 框架实现&#xff0c;能够执行 C# 代码。Unity 使用 Mono 来处理 C# 脚本&#xff0c;并通过 JIT&#xff08;Just-In-Time&#xff09;即时编译器将托管代码转换为本地机器代码&#xff0c;随后在目标平台上执行 IL2CPP 代表 Intermediate Lang…

《业务三板斧:定目标、抓过程、拿结果》读书笔记3

关于目标&#xff0c;关键是共识目标&#xff1a; 为什么不是共识目标&#xff0c;而是共信目标&#xff1f; 共识目标是指管理者通过沟通&#xff0c;让所有团队成员就目标以及实现目 标的方法达成一致。当个人与组织、个人与个人之间出现“路径选择 差异”的时候&#xff0c;…

算法专题四: 前缀和

目录 1. 前缀和2. 二维前缀和3. 寻找数组的中心下标4. 除自身以外数组的乘积5. 和为k的子数组6. 和可被K整除的子数组7. 连续数组8. 矩阵区域和 博客主页:酷酷学!!! 感谢关注~ 1. 前缀和 算法思路: 根据题意, 创建一个前缀和数组, dp[i] dp[i -1] arr[i], 再使用前缀和数组,…

Go编译为可执行文件

在window下打包成其他系统可运行的文件 1.在window下打包成window下可执行文件 在项目main.go同级目录下&#xff0c;逐条执行以下命令 set CGO_ENABLED0 set GOOSwindows set GOARCHamd64 go build -o main-windows.exe main.go 2.在window下打包成linux 在项目main.go同级目…

Android Codec2 CCodec(十六)C2AllocatorGralloc

这一篇文章我们一起来瞧瞧2D&#xff08;Graphic&#xff09; buffer分配器C2AllocatorGralloc是如何工作的。 1、GraphicBuffer 在Android系统中&#xff0c;GraphicBufferAllocator和GraphicBufferMapper是与图形缓冲区&#xff08;Graphic Buffers&#xff09;管理相关的重…

Python爬取b站视频:验证cookie是否有效

具体代码 import requestsheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0,Referer: https://www.bilibili.com/,Origin: https://www.bilibili.com } def readCooki…