mysql “可重复读“ 解决了哪些问题,没有解决哪些问题?

可重复读解决了更新带来的不可重复读问题,但是没有解决插入或者删除带来的幻读问题。这句话,是老八股文了。
但真实情况是这样的吗?这个验证不麻烦,我们可以动手来验证一下。
我使用的是免安装版本的windows mysql8.0.31,用power shell登录mysql客户端,命令行操作mysql。
搞一个测试表user1,里面有一条初始化数据,如下:
在这里插入图片描述
看一下mysql默认的隔离级别
select @@transaction_isolation;
在这里插入图片描述
可以看到mysql的默认隔离级别就是可重复读,我们不用修改。
下面开始操作。
1、事务A,执行begin,然后执行update语句,将name由"张三"改成"李四",此时先别提交。
在这里插入图片描述
2、事务B,执行begin,然后执行select语句,此时也别提交。
在这里插入图片描述
事务B为什么要执行一个select语句?
其实是,如果我们只是执行一个begin命令,此时mysql不会产生事务。
在这里插入图片描述
需要执行一个命令才会有事务,不一定是select,其他语句也可以。
在这里插入图片描述
然后事务A的update语句提交,如下图。可以看到,事务A提交后,再次查询id=1的数据,name已经由"张三"变成了"李四"
在这里插入图片描述
我们再看一下事务B的窗口,执行一下select。
在这里插入图片描述
可以看到,id=1的name字段还是"张三",并没有发生变化。
至此,我们就验证了:“可重复读” 隔离级别下,确实可以解决更新语句带来的 “不可重复读” 问题。
那是否解决了幻读呢?
我们在事务A插入一条语句,提交。
在这里插入图片描述
在事务A可以看到,新增了一条数据,id=2,name=“王五”
按照八股文的说法,我们此时在事务B执行select,应该是可以看到新增的这条id=2的数据的。
我们验证一下,在事务B上执行查询。
在这里插入图片描述
并没有看到新增的数据!
嗯?难道mysql的"可重复读"隔离级别解决了幻读问题吗?
如果是这样,那Serializable隔离级别就没啥意义了吧?
实际上,mysql的"可重复读"隔离级别解决了select的幻读问题,没有解决update、insert、delete的幻读问题,怎么理解呢?
我们举个例子。
事务A再执行一个语句,插入一个id=3,name="李四"的数据,
insert into user1 (id,name) values (3,“李四”);
执行完,提交。可以看到新增成功。
在这里插入图片描述
回到事务B,执行一个更新语句,将表中name字段为"李四"的数据都改成aaaaaa
update user1 set name = “aaaaaa” where name = “李四”;
如果可重复读能解决更新语句带来的幻读问题,我们看到的结果应该是:

idname
1aaaaaa
2王五

但实际上,是这样的

idname
1aaaaaa
2王五
3aaaaaa

这说明,事务B读到了事务提交的insert语句,然后将其name字段改为了aaaaaa,所以"可重复读"隔离级别并没有解决insert的幻读问题,同理update、delete也是一样的。
那是什么原因导致的以上情况呢?
这里面涉及到两个概念,快照读、当前读。
先说快照读。
在事务A开启事务,未提交事务时,事务B开启了事务,执行了查询操作,此时事务B读取的就是数据库的一个快照。事务A此时操作数据提交,影响不到事务B的读操作,因为MVCC的缘故。MVCC其实就是借助版本号,结合undo日志实现,有时间再写一下这个,此处按下不表。
但是事务B如果执行update、delete、insert,这就不是快照读了,而是当前读,读取的是表最新的数据。类似于select …for update操作。
如果事务B执行select操作,并且想读到最新的数据。有2个方法。
一个是加select+for update,执行当前读。
另一个就是等待事务A提交后,再开启读事务。
除此之外,我们还可以上更高的隔离级别:serializable级别,也就是串行化。这个级别是怎么解决以上问题的呢?
事务A开启事务执行insert语句。
在这里插入图片描述
事务B开启事务执行select语句,如下图:
在这里插入图片描述
可以看到,select直接卡住,然后等待锁超时了,也就是说在serializable级别下,写请求没有提交时,不允许开启其他事务。
参考:
1、https://dev.to/techschoolguru/understand-isolation-levels-read-phenomena-in-mysql-postgres-c2e
2、https://blog.csdn.net/qq_43295093/article/details/120561978

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MySQL可重复读级别是解决了部分幻读的问题,但并没有完全解决。幻读是指在一个事务中,当某个范围内的记录被其他事务插入或者删除时,当前事务再次读取该范围的记录时,会出现不一致的现象。 在MySQL可重复读级别下,使用了行级锁来保证事务的隔离性,防止并发事务之间相互干扰。具体而言,可重复读级别使用了next-key锁,将索引的范围加上了锁,防止其他事务对该范围内的记录进行插入或者删除操作。这样可以确保在一个事务中多次读取同一范围的记录时,结果始终相同,避免了读取到其他事务插入或删除的幻影行。 然而,可重复读级别并不能完全解决幻读问题。因为它只能保证在同一个事务内,对同一范围的查询结果是一致的,但无法防止其他事务在当前事务查询过程中插入新的记录或者删除现有的记录,从而导致幻读。也就是说,对于已经存在的记录,可重复读级别可以保证读取的结果是一致的,但对于新插入的记录,则无法预测是否会被查询到。 为了解决幻读问题MySQL引入了更高的隔离级别,如串行化。在串行化级别下,对于同一范围的查询结果,在事务开始和提交之间都会加上行级锁,防止其他事务对该范围内的记录进行插入或者删除操作,从而完全解决了幻读问题。但需要注意的是,在串行化级别下,可能会导致并发性能下降,因为所有的事务都需要按照先后顺序依次执行,无法并发进行。 综上所述,MySQL可重复读级别可以解决部分幻读问题,但无法完全解决。为了彻底解决幻读问题,需要使用更高的隔离级别,如串行化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值