自学内容网 自学内容网

MySQL-事务

目录

🌘为什么使用事务

🌓事物的概念

🌖使用

🌕事务的基本特性


🌘为什么使用事务

事务是用来解决一类特定场景的问题的,有些场景中,完成某个操作,需要多个SQL配合完成

例如下面的转账过程

drop table if exists accout;
create table accout(
id int primary key auto_increment,
name varchar(20) comment '账户名称',
money decimal(11,2) comment '金额'
);
insert into accout(name, money) values
('阿里巴巴', 5000),
('四十大盗', 1000);

比如说,四十大盗把从阿里巴巴的账户上偷盗了2000元

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

📛假如在执行以上第一句SQL时,出现网络错误,或是数据库挂掉了,阿里巴巴的账户会减少2000,但是四十大盗的账户上就没有了增加的金额。

解决方案:使用事务来控制,保证以上两句SQL要么全部执行成功,要么全部执行失败。

🌓事物的概念

事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。在不同的环境中,都可以有事务。对应在数据库中,就是数据库事务。

所谓事务,就相当于是把多个要执行的SQL,打包成一个"整体”,这个"整体”在执行过程中就能够做到要么整个都执行完,要么就一个都不执行.就可以避免出现上述转账一半的中间状态

此处的"一个都不执行"不是这些SQL真的没执行,而是执行一半,发现出错的时候数据库会自动进行"还原操作",相当于把前面执行过的SQL给进行"撤销”,最终的效果就看起来好像是一个都没执行这样的效果。这样的机制,称为"回滚"(rollback)。同时,也把事务支持的上述的"特性"称为"原子性”(过去人们以为"原子"就是不可拆分的最小单位了)。

数据库如何知道,具体是怎样回滚的?如何知道,前面的SQL做出了啥样的修改呢?
数据库内部存在一系列的"日志体系”,记录到"文件中”,既可以应对"程序崩溃",也能应对"主机掉电”(虽然掉电,但是回滚的日志还是存在的,此时下次主机上电,下次数据库启动的时候就可以根据回滚日志的内容,就进行回滚操作了)。当开启事务的时候,此时每一步执行的SQL,都对数据进行了哪些修改,这些信息就会记录在案,后续如果需要回滚,就可以参考之前记录的内容,进行还原了。

问题来了,drop database这样的操作能回滚回来吗?不能的
☘️回滚操作,只是针对"事务”来说的
☘️开启事务之后,就会记录回滚日志,事务执行过程中,出现问题,自动触发回滚
☘️一方面,这样的操作不能放到事务中去执行
☘️另一方面,这个操作,也不算执行出错,算是"正确执行了SQL"

☘️开启事务之后,一个事务内,虽然是执行多个SQL,执行的内容也不能太多

🍀事务最核心的特性,就是原子性,能够解决的问题,就是批量执行SQL的问题,
🍀除了转账之外,还有新生登记(可能需要往学生表/班级表同时插入数据)
🍀电商网站上下单(可能需要改商品表的库存数据/新增订单数据)

🌖使用

(1)开启事务:start transaction;
(2)执行多条SQL语句
(3)回滚或提交:rollback/commit;

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

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

🌕事务的基本特性

关于事务,在面试中,除了问你基本的概念(上面的内容),还会考察到一个比较麻烦的东西:事务的基本特性
事务涉及到四个核心特性.
1.原子性(最重要的特性)
2.一致性.描述的是,事务执行前和执行后,数据库中的数据,都是'合法状态',不会出现非法的临时结果的状态
3.持久性.事务执行完毕之后,就会修改硬盘上的数据.事务都是会持久生效的
4.隔离性.描述了多个事务并发执行的时候,相互之间产生的影响是怎样的,MySQL是一个"客户端-服务器"结构的程序,一个服务器,通常会给多个客户端同时提供服务因此,很可能,这多个客户端,就同时给这个服务器提交事务来执行,与之相对,服务器就需要同时执行这多个事务,此时就是"并发"执行,此时,如果这些同时执行的事务,恰好也是针对同一个表进行一些增删改查,此时就可能会引入一些问题。
1)脏读

有两个事务A和B并发执行,其中事务A在针对某个表的数据进行修改,A执行过程中,B也去读取这个表的数据,当B读完之后,A把表里的数据又改成别的。这就导致,B读到的数据,就不是最终的"正确数据",而是读到了临时性的,"脏数据”(往往指的是"数据过期,过时了"
错误的数据了)。

⚠️解决方案:在修改的时候给写操作“加锁”,不可读。

2)不可重复读

🐣此时,有三个事务,ABC
🐣首先,事务A执行一个修改操作.A执行完毕的时候,提交数据.
🐣接下来事务B执行,事务B读取刚才A提交的数据
🐣在B读取的过程中,又来了一个事务C,C又对刚才A修改的数据再次做出了修改
🐣此时对于B来说,后续再读取这个数据,读到的结果就和第一次读到的结果是不一样的
🐣这个过程就叫做"不可重复读"
🐣体现的是事务B,在一个事务里多次读取的结果不一样
🐣如果是有多个事务,每个事务读到的数据不一样,这种情况认为是正常的

⚠️解决方案:给读操作“加锁”,一个事务在读取数据的过程中,其他的事务不能修改它正在读的数据

3)幻读问题

有一个事务A在读取数据,读的过程中,另外一个事务B,新增了/删除了一些其他的数据…此时站在A的视角,多次读取的数据内容虽然一样,但是"结果集”不同。

⚠️解决方案:“串行化”,比如多个客户端,同时提交了多个事务过来,但是服务器一个一个的执行事务(执行完第一个事务,再执行第二个,再执行第三个…)


在MySQL中提供了四个隔离级别.可以通过配置文件来设置当前服务器的隔离级别是哪个级别
设置不同的隔离级别,就会使事务之间的并发执行的影响产生不同的差别,从而会影响到上述的三个问题的情况
1)read uncommitted 读未提交,

🍂这种情况下,一个事务可以读取另一个事务未提交的数据,
🍂此时,就可能会产生脏读,不可重复读,幻读三种问题
🍂但是此时,多个事务并发执行程度是最高的,执行速度也是最快的

2)read committed 读已提交

🍃这种情况下,一个事务只能读取另一个事务提交之后的数据(给写操作加锁了)
🍃此时,可能会产生不可重复读,幻读问题(脏读问题解决了)
🍃此时,并发程度会降低,执行速度会变慢,同时也称为事务之间的隔离性提高了,事务之🍃间的相互影响变小了,得到的数据更准了

3)repeatable read 可重复读

🍁这个情况下,相当于是给写操作和读操作都加锁了.
🍁此时,可能产生幻读问题,解决了脏读和不可重复读问题,
🍁并发程度进一步降低,执行速度进一步变慢,事务之间的隔离性,进一步提高了.

4)serializable 串行化     MySQL默认的隔离级别

🍀此时,所有的事务都是在服务器上一个接一个的执行的,
🍀此时,解决了脏读,不可重复读,幻读问题
🍀并发程度最低,执行速度最慢,隔离性最高,数据最准确

根据需要,看需要执行速度快,还是数据比较准,来选择合适的隔离级别
准和快,无法兼得~


原文地址:https://blog.csdn.net/2301_80141037/article/details/145199478

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!