实操事务的四大隔离级别以及浅解三大读(脏读、不可重复读、幻读)现象

1.事务的隔离级别

  • 首先我们先了解一下什么是事务的隔离级别

下面介绍一下事务的四大隔离级别:

  1. 读未提交(READ_UNCOMMITTED):最低隔离级别,允许读到未提交的事务中的数据变更,会导致脏读现象
  2. 读已提交(READ_COMMITTED):Oracle数据库默认隔离级别,允许读到已提交事务的数据,解决了脏读现象,当前事务不能保证想读的数据前后读取一致,也就是不可重复读,这种隔离级别不能解决。
  3. 可重复读(REPEATABLE_READ):MySQL数据库默认隔离级别,事务对同一字段或记录的多次读取结果都是一样的,解决了脏读和不可重复读现象,但是会出现幻读现象。
  4. 可串行化(SERIALIZABLE):事务最高隔离级别,完全遵循得物的ACID特性,所有事物排依次执行,对操作的数据加锁,当前事务未提交时其他事物不能操作。解决了脏读、不可重复读、幻读。

2.事务的隔离级别引发的三大读现象(脏读、不可重复读、幻读)

  • 可能上面的概念有些懵,这脏读、幻读、不可重复读是什么啊?在这里浅浅的解释一下:
  1. 脏读现象:脏读指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,**也就是不存在的数据,这些数据是脏数据。**读到了并不一定最终存在的数据,这就是脏读。例子:事务B的更新数据被事务A读取,但是事务B回滚了,更新数据全部还原,也就是说事务A刚刚读到的数据并没有存在于数据库中。
  2. 不可重复读现象:不可重复读指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况。事务 A 在某种业务情况下需要多次读取同一数据,但事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
  3. 幻读现象:当同一个查询在不同的时间产生不同的行集时,事务中就会出现所谓的幻影问题。例如,如果SELECT执行了两次,但第二次返回的行不是第一次返回的,那么该行就是“幻影”行。

为了更好的了解事务的隔离级别和这些读现象,我们来实时演示一下事务:

3.演示事务

(1)演示读未提交

演示读未提交(READ_UNCOMMITTED):

  1. 可以看到,我们现在的隔离级别是mysql默认隔离级别为RR(可重复读),现在我们修改事务的隔离级别为RU(读未提交)

我们先查看一下当前事务隔离级别:

# 查看当前事务隔离级别
show variables like 'transaction_isolation';

接着我们修改事务隔离级别为RU(读未提交)切记我们设置完事务的隔离级别后,需要将窗口关闭,然后再次打开才会生效!注意测试完后记得改回去哈!

# 设置事务级别为读未提交,这是设置全局的,用完之后记得该回到可重复读哈!
set global transaction isolation level read uncommitted;

  1. 设置完隔离级别后,我们开启两个小黑窗口,分别开启事务,暂且称为事务A和事务B,首先我们查询我的userdb数据库中的tb_user表的数据。
# 开启事务
start transaction;

事务A:

事务B:

  1. 现在我们在事务A中查询id为40的记录,接着我们修改这条记录的年龄为20;

  1. OK,现在我们不要动事务A,跑到事务B这里来查询同一条记录,此时我们的事务A是没有提交的

  1. OK,现在我们回滚事务A,查询数据库中数据
# 回滚事务
rollback;
# 提交事务
commit;

OK,结束显示完毕,可以看到,我们在事务A没有提交的情况下,事务B读到了事务A所修改但未提交的数据,这就是数据库中的读未提交(READ_UNCOMMITTED)隔离级别。

问题:事务B读到了事务A未提交的数据,但是事务A并没有采用这条数据,并将它回滚了,这条数据我们称为脏数据,而事务B读取这条读数据的行为就被称为脏读现象

(2)演示读已提交

演示读已提交(READ_COMMITTED):

  1. OK,我们重新设置mysql数据的隔离级别为读已提交RC,操作和上面差不多我就省略了哈。
set global transaction isolation level read committed;
  1. 现在我们来修改事务A中的数据,还是修改年龄为18

  1. 此时,我们使用事务B查询统一条记录,注意此时事务A是没有提交的。

OK,这就是事务中的读已提交RC的隔离级别,事务B只能读到事务A已提交后的数据,这样避免脏读现象。

问题:就是我事务B在某种业务情况下,要求前后读到的数据要一致,此时当我事务A提交事务后,事务B多次读取到的同一数据前后不一致了,这就是我们所谓的不可重复读现象

(3)演示可重复读

演示可重复读(REPEATABLE_READ):

  1. 修改mysql数据的隔离级别为可重复读
set global transaction isolation level repeatable read;
  1. 重复之前演示读已提交的操作,事务A修改id为40的记录年龄为18(之前修改成20了),事务B去读取,在事务A未提交的情况下;随后事务A提交,事务B再次读取该数据。发现事务B读取的数据都一样,这就是可重复读隔离级别RR

事务A:

事务B:

问题:

但是这种隔离级别还是存在问题,会产生幻读现象。什么是幻读,网上关于这个理解有很多,而我在这里提出自己的理解,我也是个初学者,理解不到位还请见谅。

关于幻读的理解

参考博客:(一文详解脏读、不可重复读、幻读_脏读 幻读 不可重复读_啊啊啊啊啊北的博客-CSDN博客)

这是官方文档解说:The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.

当同一个查询在不同的时间产生不同的行集时,事务中就会出现所谓的幻影问题。例如,如果SELECT执行了两次,但第二次返回的行不是第一次返回的,那么该行就是“幻影”行。

我的理解:幻读和不可重复读是有相似之处的,但是还是不一样的。

不可重复读是在同一事务内读到了不同的数据,事务查到的数据前后一致性我不保证,新增的其他数据我不管照查。前一次我查到了A、B,后一次我查到了A、B、C。但是我不保证我前后查出来的A、B数据一致,其他事物修改了A、B提交,我也一并查出来。

而幻读查对于新增的数据就要管一管了。

幻读是在RR隔离级别下,同一事务提交前所多次读取到的同一条件的数据集合是一致的情况下,但是又存在其他事务执行的操作对当前事务的影响是实实在在的,当前事务却感知不到。而当前事务去操作的时候,这份影响又存在,就像幻觉一样,前一次我查询出来A、B,后面有事务插入了C,但是我再次查询时,显示的还是A、B,C查不出来,当我执行插入C的时候却发现插入不了,当我提交事务后,再次执行查询到了C,那么C这行的数据就是“幻影行”。

业务场景:

  1. 现在我有两个事务,事务A和事务B,数据库的隔离级别为可重复读RR
  2. 以我上面表的数据为例(太懒了就不做实操了),现在我的事务A查询数据只有id为39、40两条。
  3. 此时事务B向数据库中插入了一条id为41的数据,并且提交事务。
  4. 事务A不知道事务B插入了一条数据,但是保险起见它又查询了一次,此时它读到的数据还是只有两条。
  5. 现在事务A确信没有其他数据了,所以放心大胆的向数据库中插入了一条id为41的数据,但是却报错了。
  6. 报错的原因是主键重复,好,事务A懵逼了,妈耶大白天遇到“鬼打墙”了,我查出来数据库确实没有这条记录啊,怎么插不进去嘞。

举个例子:云南的朋友应该很好理解,我在野外采了我不知道的菌子(假设有毒的),我拿回去煮了吃了中毒了(开启事务),吃完之后我飘飘欲仙,爽得要死。此时,现在有个人跑过来给了我的腿两闷棍,因为中毒的原因我不知道别人给了我两闷棍,第一时间感受不到痛(当前事务感觉不到,或者感觉是错的),但是当我要去走的时候却发现腿骨折了怎么都走不动(其他事务的影响是实实在在的),吃菌子中毒却让我认为别人并没有打我,我的身体还是好的,诶我明明身体是好的但是却走不了路了怎么回事。等我毒性消失(事务提交)才缓过来我被打了并且立马找他讹十万块,可以带入理解一下幻读。

所以可以进一步理解,引用我上面参考博客里面的话,“幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。

(4)演示可串行化

演示可串行化(SERIALIZABLE):

  1. 修改mysql数据的隔离级别为最高级别可串行化
set global transaction isolation level serializable;
  1. 开启事务A,事务B,事务A修改表中数据,id = 39 年龄age为20,修改成功,此时事务B也开始修改这条数据,但是发现修改不了。

事务A:

事务B:

  1. OK,现在事务A提交,我们事务B再次操作这条数据试试看。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3bdr6mgX-1691218471498)(assets/image-20230805144851702.png)]

OK,这就是事务的最高隔离级别可串行化,所有的事务一个一个运行,不可并行。这个隔离级别会在当前事务所操作的数据添加一道行锁,在这个事务里面操作的数据其他事务都操作。解决了三大读问题,该隔离级别完全遵循事务的ACID原则。

  • OK,演示到此结束,初学者的学习,如果有不到位还请见谅,希望帮忙指出,谢谢!
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值