Mysql进阶

mysql 进阶 事务隔离级别

最近一段时间闲来无事,写篇文章,算是对大一学习mysql的一个回顾吧

何谓事务 ?他就好比为一个操作单元,这个操作要么执行,要么不执行。例如,我们四条增删查改的sql,归为一个事务,如果这四条sql有一个执行失败则其余三条通通失效(回滚)。当事务执行时也无法被其他事务干扰,也就是说并发时事务是隔离的,互不影响。同时,事务如果执行成功,对数据库将产生持久的影响。

以上介绍就表明了事务的几大特性:

  • 原子性
  • 隔离性
  • 一致性
  • 持久性

ok,回到正题,mysql的事务隔离级别如下:

  • 序列化:隔离级别最高,同时也是效率最低
  • 可重复读:mysql默认隔离级别
  • 读提交:
  • 读未提交:
读未提交实践

假设我们有如下一张商品表:

image-20221125210220376

good_id商品id
good_num商品数量
good_name商品名字

首先,通过如下sql查看当前事务隔离级别

SELECT @@GLOBAL.tx_isolation, @@tx_isolation;

查询结果如下图

image-20221125201705038

全局和当前会话的都为可重复读,现在从读未提交开始研究。首先,修改当前会话隔离级别为读未提交

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

可以看到修改结果如下图

image-20221125202301513

接下来,打开两个窗口,用来表示两个事务。这里的 B窗口我们已经修改成读未提交。

现在,在 A 窗口输入如下语句,但是不执行

START TRANSACTION;
UPDATE goods_info SET good_name = "羊肉"
update  goods_info set good_name = "牛肉"

COMMIT;

然后在 B 窗口输入如下语句,但是不执行

START TRANSACTION;
SELECT good_name FROM goods_info

SELECT good_name FROM goods_info
commit;
脏读
  1. 执行 A B 窗口的第一句(执行顺序无所谓),分别开启事务
  2. 执行 B 窗口第二句,查询商品名字发现结果如下

image-20221125221353799

  1. 执行 A窗口的第二句,再执行 B 窗口的第三句,得到查询结果 为 羊肉

由于事务是互不影响的,而此时 B 事务 读取到了 A 事务未提交的数据,那这就就是脏数据, 也叫脏读。

不可重复读
  1. 执行 A B 窗口的第一句(执行顺序无所谓),分别开启事务
  2. 执行 B 窗口第二句,查询商品名字发现结果 为 牛肉
  3. 执行 A窗口的第二句,并提交 A 事务。再执行 B 窗口的第三句,得到查询结果 为 羊肉

这和脏读的本质区别在于:脏读读的是未提交的数据,而不可重复读读取的是其他事务已经提交的数据,(按照隔离性的理论,事务之间是互相不干扰的。)

幻读

看名字就是产生幻觉了。

A 窗口 有如下语句

START TRANSACTION;
insert into goods_info values(”牛肉干“);

commit;

B 窗口 有如下语句

START TRANSACTION;
select * from goods_info

delete from goods_info  where good_name = "牛肉干"
commit;

开始测试:

  1. 执行 A B 窗口的第一句(执行顺序无所谓),分别开启事务
  2. 执行 A 窗口的第二句,不提交
  3. 执行 B 窗口的第二句,可以查到 good_name 为 牛肉干 的一条记录
  4. 执行 B 窗口的第三句,却发现无法删除,(0 条记录被影响)

明明可以查询 牛肉干 的商品,删除的时候却没有,这出现幻觉了。(实际上因为 a 事务 并未提交),好了通过以上介绍,相信大家已经明白了什么是 脏读,不可重复读,幻读

读提交实践

读提交主要是解决了脏读的问题,而不可重复读,幻读则没有得到解决。前两个可以通过上面的测试例子,但是幻读需要换一个新例子。

幻读

A 窗口 有如下语句

START TRANSACTION;
INSERT INTO goods_info VALUES(2,0,0,"牛肉")

commit;

B 窗口 有如下语句

START TRANSACTION;

SELECT * FROM goods_info

INSERT INTO goods_info VALUES(2,0,0,"牛肉")

commit;

开始测试:

  1. 执行 A B 窗口的第一句(执行顺序无所谓),分别开启事务,然后执行 A 窗口的第二句

  2. 执行 B 窗口的第二句,结果如下:image-20221126133326558

  3. 执行 B窗口的第三句,此时发现锁超时了,明明没有却无法插入,便出现了幻觉

可重复读

是mysql 默认的隔离级别,主要解决了脏读,不可重复读,幻读依旧没有解决。与都提交的测试样例一样,只不过 A 窗口插入一条后,马上提交事务再执行后面的步骤。

序列化(SERIALIZABLE )

SERIALIZABLE 提供了事务之间最大限度的隔离,在这种隔离级别中,事务一个接一个顺序的执行,不会发生脏读、不可重复读以及幻象读问题,最安全。

如果设置当前事务隔离级别为 SERIALIZABLE,那么此时开启其他事务时,就会阻塞,必须等当前事务提交了,其他事务才能开启成功,因此前面的脏读、不可重复读以及幻象读问题这里都不会发生。但是这样的效率极其低下。

总结

给出一张 MySQL 隔离级别的对比图

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值