MySQL初阶3——事务的初步理解

news2024/11/23 13:35:57

目录

一、事务的引入⭐⭐⭐⭐⭐

1. 为什么需要事务

2. 事务的四大特性

二、事务的具体细节⭐⭐⭐⭐⭐

1. 事务在并发会遇到的三种常见问题

2. MySQL事务隔离的四种级别

三、MySQL中如何开启事务

四、补充


很荣幸与诸君在篇文章“相遇”,祝大家身体健康,感谢大家的莅临指导!

本文分享、讨论的重点在事务的理论部分,如何开启MySQL中事务的操作也会提及,但不是重点。本文仅仅是事务的初阶知识,还有一些进阶的内容会在我接下里的MySQL进阶篇提及。

一、事务的引入⭐⭐⭐⭐⭐

1. 为什么需要事务

在日常开发中,很多操作,不是通过一个SQL就能完成,往往需要多个SQL配合完成。当执行多个SQL操作的时候,如果中间出现了特殊的情况(如程序崩溃、系统崩溃、网络断开,主机断电了……)可能就会出现,前面的SQL执行成功,后面的SQL执行失败了。

考虑场景,如:转账

当客户执行转账操作时,涉及从一个账户扣除资金并将其存入另一个账户。这个过程可能包括多个数据库操作,如查询余额、扣款和存款等。使用事务可以确保转账操作的原子性,即要么全部成功完成,要么完全不执行,从而避免出现资金丢失或不一致的情况。

 重点:这时候就需要引入事务来保证多个SQL语句要么都执行,要么都不执行!

事务,把多个操作打包成一个整体,就能够保证这个整体要么都执行成功,要么就“一个都不执行”。有效避免了部分执行,部分未执行产生一些“中间状态引起”的问题。

上面说道的要么一个都不执行 并非 是真的没有执行

事务中的若干个SQL必然是要一条一条地执行的 ~,但是事务能够保证当执行到某一条SQL语句如果出现了问题,数据库就能自动地把前面SQL造成的影响给恢复回来,恢复如初,看起来就好像一条SQL都没有执行过的样子。

重点:数据库事务的原子性,核心就是通过“回滚”机制来保证!

既然上面说到了事务的四大特性中的一个——原子性,那我们就先来讨论一下事务的四大特性。

2. 事务的四大特性

事务具有ACID四大特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(lsolation)和持久性(Durability):

(1)原子性(Atomicity):原子性指事务是一个不可分割的工作单位,要么全部执行成功,要么全部执行失败回滚。在事务中的操作要么全部提交,要么全部回滚,不存在部分提交的情况。这确保了数据的完整性,即数据库在任何时候都处于一致的状态。

(2)一致性(Consistency):一致性指事务使数据库从一个一致性状态转变到另一个一致状态,不会出现数据对不上的情况。在事务执行前后,数据应该保持一致性。如果事务执行成功,数据应该处于一致状态;如果执行失败,则数据库应该恢复到事务开始前的状态。一致性规则由业务逻辑来定义。

(3)隔离性(Isolation)⭐⭐⭐⭐⭐隔离性指多个事务并发执行时,每个事务的操作应该与其他事务隔离开来,互不干扰。事务之间应该是相互独立的,避免数据相互影响。隔离级别可以控制事务之间的可见性和影响范围,常见的隔离级别包括读未提交、读已提交、可重复读和串行化

具体描述如:数据库并发执行事务(多个客户端同时给服务器发起事务),每个客户端啥时候把事务提交过来?服务器不知道,很可能多个客户端正好就把事务赶到一块了,就需要数据库服务器都能给出处理,更糟糕的是,如果这多个事务都尝试操作同一个表,情况会变得更糟!就类似于“一心多用”,这时候就需要数据库服务器把这多个事务都能处理好。

重点:在下面还会进一步讨论事务的隔离性及其事务在并发会遇到的三种常见问题!

(4)持久性(Durability):持久性指一旦事务提交,其对数据库的修改应该是永久性的,即使系统发生故障也不会丢失。系统必须能够保证事务提交后对数据的修改是持久的,并能够在系统故障后恢复数据。持久性通常通过日志记录和数据备份来实现 。

总结:这四大特性确保了事务的正确性、可靠性和稳定性,是数据库管理系统保证数据完整性和一致性的重要基础。当事务满足ACID四大特性时,可以确保数据库在各种异常情况下依然能够保持数据的正确性和稳定性。

二、事务的具体细节⭐⭐⭐⭐⭐

1. 事务在并发会遇到的三种常见问题

(1)脏读(Dirty Read):

  • 产生原因:脏读指一个事务读取了另一个事务未提交的数据。当一个事务修改了数据但尚未提交,另一个事务读取了这个未提交的数据,就会导致脏读。
  • 处理方式:避免脏读的方法是使用适当的隔离级别,如读已提交(Read Commited) 或串行化(Serializable) 隔离界别。读已提交隔离级别可确保一个事务只能读取到已提交的事务,从而避免的脏读。

举个例子:

有位老师在备课,在计算机上敲了一段代码,这时有位同学路过的时候,偷偷瞄了一下老师的屏幕,看到屏幕上的一段代码,于是暗暗记下来了。当这位同学看完走后,老师把这段代码一改,最终在老师上课讲的代码和同学瞄到的代码可能不一样了。诶,这就像极了脏读,那么如何解决呢?

解决方案:

老师和同学们作了个约定,大家以后不要再瞄我的屏幕了。如果想提前预习课程,提前看到代码,可以去老师的码云上看。诶,这个解决方案是不是就是类似于隔离级别读已提交,同学们只能去读老师已经提交到码云上的代码。

这是对“读”或“写”上锁呢?各位小伙伴们想一想。

答:上述约定,就相当于是针对“写操作”加锁,我这边写的时候(啪一下~,把房门一关,诶,同学们就没办法偷偷瞄老师屏幕上的代码,读到老师提交的代码),你不能读,只有当我写完,你才能读。

现在引入了写加锁之后,执行写操作事务A的过程中,读操作事务B就不能执行了,要等待。这就相当于降低了“并发能力”,也就会降低数据库服务器的处理效率,提高了“隔离性”,也提高了数据的准确性。

(2)不可重复读(Non-Repeatable Read):

  • 产生原因:不可重复读指一个事务在多次查询同一个数据时,由于其他事务的修改导致数据不一致。例如:一个事务在两次读取同一数据之间,另一个事务修改了该数据,导致了一个事务两次读取的数据不一致。
  • 处理方式:可重复读隔离级别可以避免不可重复读问题。在可重复读隔离级别下,一个事务在多次读取同一数据时,其他事务对该数据的修改不会影响到第一个事务的结果。

举个例子:

顺成了上一个栗子的情况,老师已经和同学们约定好了,同学们只能来读取老师提交到码云的代码。现在,老师写了一些代码(事务A),把代码提交到码云了,有同学发现老师的码云更新了(1min之前),同学们赶紧来读代码(事务B)。诶,这个时候老师突然想到之前提交的代码有问题,还得修改修改,赶紧改了代码后,重新提交了(事务C)

其中的事务B:同学读的过程中,本来看到的都是事务A中的结果,读着读着,代码突然就变了!!!(因为老师重新提交了代码)

诶,上述的栗子就是在说明同学们无法重复读老师重新提交的数据,称为“不可重复读问题”。

存在三个事务 ABC,事务A针对数据进行的修改、提交;接下来事务B进行读取数据(事务B这里的多个SQL都要进行读操作),在执行B的过程中,又有一个事务C针对数据进行修改,就会使事务B中的不同读操作,读出来的结果不一样。

 “读已提交”是对“写操作”进行上锁了,而没有约定读的时候“不能写”。那么如何解决“不可重复读问题”呢?再进一步约定,给读操作也加锁!

  • 写操作加锁:我写的时候,别人不能读;
  • 读操作加锁:别人读的时候,我不能写;

对照我们上面的栗子:就是和同学们进一步约定,老师提交代码之后,就不要改了,同学们读完之前,这个时候老师都不能修改了。

此时引入了读加锁,就会使得“并发程度”又进一步降低。效率也会随之降低“隔离性”又进一步提高,数据的准确性也会提高,这个时候事务A、B、C就不能笔法执行了。

(3)幻读(Phantom Read):

  • 产生原因:幻读指一个事务在两次查询之间,另一个事务插入了新的数据,导致第一个事务第二次查询看到了不一致的数据。这种情况通常发生在范围查询操作中。
  • 处理方式:使用更高级别的隔离级别,如可重复读(Repeatable Read) 或串行化隔离可以避免幻读问题。这些隔离级别可以确保一个事务在执行期间可以多次读取相同的数据,从而避免出现幻读的现象。

举个例子:

刚刚约定了,针对“读操作”和“写操作”都加锁了。

比如,老师写了代码,提交了,同学们开始读代码,按约定来说,此时老师不能修改代码。

但是老师这时闲着没事,虽然不修改代码,但是老师创建了一个新的类/文件,针对新的类/文件进行修改,并提交~。这样做,虽然同学们读到的代码是一样的,但是发现多出来新的文件。

事务A先修改并提交数据,事务B进行读数据,此时事务C没有修改事务B读的数据,但是给对应的表进行了新增数据 / 删除数据等操作……,导致事务B中,读到的数据级不同。

解决方案:

“串行化”使得所有的事务都严格按照“一个接一个”的方式执行,完全没有并发了,此时执行效率是最低的,隔离性也是最高的,数据也是最准确的。

总结:上述三个问题,就是在并发执行事务过程中,可能会产生的三个典型问题。

  • 脏读:事务B读到了事务A中未提交的临时数据(脏数据)=> 写加锁
  • 不可重复读:事务B读的过程中,又有一个事务C对刚才的事务A提交的数据进行了修改,使事务B内部不同的读操作读到的结果不同 => 读加锁
  • 幻读:和不可重复读类似,事务B读的过程中,事务C没有修改数据内容,而是修改了“结果集”,导致B内部不同的读操作读到的结果集合不同。

解决上述的问题过程中,要想让数据更准确,就需要牺牲一部分并发/效率,很难做到又高效又准确。只能做“权衡”,看你当前业务常见,是更关注效率,还是更关注准确性。

重点:这里最难区分就是“不可重复读”和“幻读”,我和诸位进一步讨论下~

幻读(Phantom Read)和不可重复读(Non-Repeatable Read)是数据库并发控制中两种不同的现象,它们的区别如下:

  1. 幻读(Phantom Read)

    • 定义:幻读指在一个事务内部,由于其他事务插入或删除数据,导致同一查询在不同时间点返回不同数量的数据行的现象。
    • 产生原因:幻读通常发生在范围查询操作中,当一个事务在读取某个范围的数据时,另一个事务在该范围内插入了新的数据,导致第一个事务多次查询时看到了不同数量的数据行。
    • 解决方法:避免幻读可以通过使用更高级别的隔离级别,如可重复读(Repeatable Read)或串行化(Serializable)隔离级别。
  2. 不可重复读(Non-Repeatable Read)

    • 定义不可重复读指一个事务在多次读取同一数据时,由于其他事务的修改导致数据不一致的现象。也可以理解为一个事务在两次读取同一数据之间,另一个事务修改了该数据。
    • 产生原因:不可重复读通常发生在一个事务进行读取操作时,另一个事务对相同数据进行了修改操作,导致第一个事务两次读取的数据不一致。
    • 解决方法:可重复读(Repeatable Read)隔离级别可以避免不可重复读问题。在可重复读隔离级别下,一个事务在多次读取同一数据时,其他事务对该数据的修改不会影响到第一个事务的结果。

总的来说,幻读强调的是在一个范围查询中出现新增或删除数据的情况,导致查询结果不一致;而不可重复读强调的是同一事务多次读取同一数据时,由于其他事务的修改导致数据读取结果不一致的情况。在处理这两种并发问题时,需要根据具体场景选择合适的隔离级别来确保数据的一致性和正确性。

2. MySQL事务隔离的四种级别

(1)read uncommitted:允许读取其他事务未提交的数据  =>  啥事没干,没有解决脏读 + 不可重复读 + 幻读;并发程度最高,隔离性最差。

(2)read committed:只能读取其他事务提交后的数据  =>  解决了脏读,存在不可重复读和幻读,并发程度低,隔离性提高了。

(3)repeatable read:针对读操作和写操作都加锁了  =>  解决了脏读 + 不可重复读,存在幻读;并发程度又降低,隔离性又提高了。

(4)串行化(serializable):所有事务都是串行执行的 => 解决了脏读 + 不可重复读 + 幻读;并发基本没有,隔离性最高。

三、MySQL中如何开启事务

(1)开启事务:start transaction;

(2)执行多条SQL语句;

(3)回滚或提交:rollback/commit;

说明:rollback即是全部失败,commit即是全部成功。

start transaction;
-- 阿里巴巴账户减少2000
update accout set money=money-2000 where name = '阿里巴巴';
-- 四十大盗账户增加2000
update accout set money=money+2000 where name = '四十大盗';
commit;

四、补充

关于MySQL的索引和事务的细节不单单只有这些,他们一些底层逻辑也是我未来的命题之一,一些比较难、比较细节的知识点,我会放到MySQL进阶篇与诸位分享,大家一起讨论。

愿与诸君共勉,加油!

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

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

相关文章

UnityShader:IBL

效果: 实现: Shader "MyShader/IBL" {Properties{_CubeMap ("环境贴图", Cube) "white" {}_Exposure("曝光",float)1.0_Color("颜色",color)(1,1,1,1)_NormalMap("法线贴图",2d)"bu…

JS仿淘宝滚动刷新简单实现

废话不多说&#xff0c;直接上代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title></title><style>* {margin: 0;padding: 0;}.box {width: 24.5%;height: 200px;float: left;}.box>…

#QT(事件--快捷键保存文件)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a;QEvent,QMouseEvent,QKeyEvent。 在上一个文本编辑器的基础上实现快捷键"ctrls"保存文件。 3.记录 &#xff08;1&#xff09;查看QEVENT的有效事件 &#xff08;2&#xff09; 所有时间均继承于QEvent&#xff0c;任…

机试:元音处理

问题描述 代码示例 #include <bits/stdc.h> using namespace std;int main(){char string[1000];char ch getchar();int i 0;while(ch ! \n){string[i] ch;ch getchar();}char str[1000];int k 0;for(int j 0; j < i; j){if(string[j] a || string[j] e || …

(含链接)2024年NVIDIA GPU技术大会开发者合集(专为开发者挑选的合集)

2024年NVIDIA GPU技术大会开发者合集 我专门为开发者整理了NVIDIA GPU技术大会上专注技术的内容合集, 希望可以帮助开发者朋友们快速了解NVIDIA的最新技术. 注意:在电脑端打开更友好, 可以直接进入每一项的网页 文章目录 2024年NVIDIA GPU技术大会开发者合集如何登录和预约会…

Nacos注册中心与配置管理

Nacos注册中心与配置管理 1 Nacos注册中心1.1.认识Nacos1.2.服务注册到nacos1.3.服务分级存储模型1.4.权重配置1.5.环境隔离1.6.Nacos与Eureka的区别 2 CAP3.Nacos配置管理3.1.统一配置管理3.2.bootstrap了解3.3.配置热更新3.4.配置共享 1 Nacos注册中心 1.1.认识Nacos 国内公…

【经验总结】ubuntu 20.04 git 上传本地文件给 github,并解决出现的问题

1. 在GitHub 上创建仓库 登录 GitHub 个人网站 点击 New 填写 Repository name, 以及 Description (optional) 选择 Public &#xff0c; 并添加 Add a README file 点击 Create repository github repository 创建成功 2. 设置SSH key 在本地 bash 运行&#xff1a;…

Android Kotlin(五)数据流StateFlow和LiveData

Android 上的 Kotlin 数据流 在协程中&#xff0c;与仅返回单个值的挂起函数相反&#xff0c;数据流可按顺序发出多个值。数据流以协程为基础构建&#xff0c;可提供多个值。从概念上来讲&#xff0c;数据流是可通过异步方式进行计算处理的一组数据序列。所发出值的类型必须…

小迪安全42WEB攻防-通用漏洞文件包含LFIRFI伪协议

#知识点: 1、解释什么是文件包含 2、分类-本地LFI&远程RFI 3、利用-配合上传&日志&会话 4、利用-伪协议&编码&算法等 #核心知识: 1、本地包含LFI&远程包含RF1-区别 一个只能包含本地&#xff0c;一个可以远程加载 具体形成原因由代码和环境配置文件决定…

PyQt5使用

安装Pyqt5信号与槽使用可视化界面编辑UI (Pyside2)ui生成之后的使用(两种方法)1 ui转化为py文件 进行import2 动态调用UI文件 安装Pyqt5 pip install pyqt5-tools这时候我们使用纯代码实现一个简单的界面 from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButto…

练习8 Web [GYCTF2020]Blacklist

这道题其实不是堆叠注入&#xff0c;但是我在联合查询无效后&#xff0c;试了一下堆叠&#xff0c;最后一步发现被过滤的sql语句太多了&#xff0c;完全没法 查阅其他wp的过程[GYCTF2020]Blacklist 1&#xff08;详细做题过程&#xff09; 是用的handler语句&#xff0c;只能用…

基于肤色模型(YCbCr模型)的人面定位统计算法,Matlab实现

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

【渗透测试】redis漏洞利用

redis安装及配置 wget http://download.redis.io/releases/redis-3.2.0.tar.gz tar xzf redis-3.2.0.tar.gz cd redis-3.2.0 make cp /root/redis-6.2.6/redis.conf /usr/local/redis/bin/ cd /usr/local/redis/bin/ vi redis.conf #修改内容如下&#xff1a; #protected-mode …

第十三届蓝桥杯(C/C++ 大学B组)

目录 试题 A: 九进制转十进制 试题 B: 顺子日期 试题 C: 刷题统计 试题 D: 修剪灌木 试题 E: X 进制减法 试题 F: 统计子矩阵 试题 G: 积木画 试题 H: 扫雷 试题 I: 李白打酒加强版 试题 J: 砍竹子 试题 A: 九进制转十进制 九进制正整数 ( 2022 )转换成十进制等于多…

【Vite+Ts】自动按需引入Element-Plus

安装插件 cnpm i -D unplugin-vue-components unplugin-auto-import unplugin-element-plus修改vite.config.ts // vite.config.ts import AutoImport from "unplugin-auto-import/vite"; import Components from "unplugin-vue-components/vite"; impor…

字符串函数和内存函数的模拟实现

目录 前言 1. 字符串操作 1.1 strncpy 1.1.1 讲解 1.1.1 模拟实现 1.2 strncat 1.2.1 讲解 1.2.2 模拟实现 2. 字符串检验 2.1 strlen 2.1.1 讲解 2.1.2 模拟实现 2.2 strstr 2.2.1 讲解 2.2.2 模拟实现 3. 字符数组操作 3.1 memcpy 3.1.1 讲解 3.1.2 模拟实…

《操作系统实践-基于Linux应用与内核编程》第10章--实验 Qt聊天程序

前言: 内容参考《操作系统实践-基于Linux应用与内核编程》一书的示例代码和教材内容&#xff0c;所做的读书笔记。本文记录再这里按照书中示例做一遍代码编程实践加深对操作系统的理解。 引用: 《操作系统实践-基于Linux应用与内核编程》 作者&#xff1a;房胜、李旭健、黄…

15届蓝桥杯第三期模拟赛所有题目解析

文章目录 &#x1f9e1;&#x1f9e1;t1_奇数次数&#x1f9e1;&#x1f9e1;思路代码 &#x1f9e1;&#x1f9e1;t2_台阶方案&#x1f9e1;&#x1f9e1;思路代码 &#x1f9e1;&#x1f9e1;t3_约数个数&#x1f9e1;&#x1f9e1;思路代码 &#x1f9e1;&#x1f9e1;t4_最…

特殊文本文件、日志技术

特殊文件 为什么要用这些特殊文件&#xff1f; 存储多个用户的&#xff1a;用户名、密码 特殊文件:Properties属性文件 特点&#xff1a; 都只能是键值对键不能重复文件后缀一般是.properties结尾的 作用&#xff1a;存储一些有关系的键值对数据 Properties 是一个Map集合(键…

Ubuntu Argoverse API安装

1. 创建并进入conda环境 conda create -n Argoverse python3.8 conda activate Argoverse2. 拉取argoverse-api源码 git clone https://github.com/argoai/argoverse-api.git3. 下载高精地图 Download hd_maps.tar.gz from Argoverse 4. 安装api cd argoverse-api pip in…