还分不清楚MySQL幻读与不可重复读吗?一个小实验帮你搞定

不可重复读与幻读一直有人分不清,而且网上对这两者的区别和解释的也不太到位,有的甚至会误人子弟。

我以我的理解解释一下幻读和不可重复读,若有错误还望指正。

希望文章中的例子可以自己实验一样,对事务的理解会更深刻。

首先看一下对不可重复读和幻读的解释

不可重复读(幻影问题):指在同一事务内,多次相同的SQL返回的结果却不同

幻读:事务A前后查询多次的结果条数是一样的,此时事务A查询的记录是不包括事务B新增的那条记录的,但是此时事务A对事务B插入的那条记录是可以执行更新操作的,操作完之后再次查询就会发现记录条数更加了一条。难以用语言描述,我这实际上是在用一个例子解释。

问题是

为什么innodb的repeatable read的隔离级别下能解决不可重复读问题而不能解决幻读问题?

因为innodb利用Next-key Locking解决不可重复读问题,每次查询会锁定记录和一个范围,以隔离本事务中已经查询过的行记录来避免其他事务的干扰,实现可重复读。但是Next-key Locking 无法解决幻读问题,因为其他事务可以修改或插入本事务中没有被锁定的范围内的数据,且本事务感知不到这种修改或插入,即原来的查询语句仍返回原来的结果。但是,本事务是可以对这种插入做修改的!因为事务B已经成功提交了,这种感知不到却能做出修改的行为就好像幻觉一样。

接下来会用实验演示,为什么会产生不可重复读,如何实现可重复读,为什么会出现幻读

数据准备如下:

create table t (a int primary key)

insert into t select 1;

insert into t select 2;

insert into t select 5;

不可重复读如下:

时间事务A事务B
1set session transaction_isolation=‘read-committed’(设置隔离级别为读已提交)
2begin;
3select * from t where a >2 for update (结果返回5)
4begin;
5insert into t select 4;
6commit;
7select * from t where a >2 for update (结果返回4,5)
10commit;

这里产生了不可重复读问题,在read-committed下,innodb会采用record Lock的方式锁定行记录,即select * from t where a >2 for update只会锁住5这行记录,所以事务B插入4成功了。

但是如果在repeatable read下,innodb会采用Next-key Lock的方式,除了锁住5这行记录以外,还会锁住a>2这个范围,因此事务B无法插入4这行记录,实现了可重复读。

但是这又产生了一个问题,只锁住了已经查询到的行记录,这里是5,还有一个范围,这里是a>2,但是还有没有被锁住的地方,比如a<2这个范围,这里就是会产生幻读的地方!

先接着恢复表中的数据还是1,2,5这三条

幻读如下:

时间事务A事务B
1begin
2select * from t where a >2 for update (结果返回5)
3begin;
4insert into t select 0;
5commit;
6select * from t where a >2 for update (结果还是返回5,但t表已经有4条记录)
7update t set a=-1 where a=0;(成功了)
8select * from t;(返回-1,1,2,5)
9commit;

事务A中select * from t where a >2 for update 会锁住a>2的所有范围,但是a<2的范围没有被锁住,因此事务B插入0会成功,

事务B提交后,t表已经有4个记录了,但是事务A可以修改a=0的记录!

幻读的命令行演示如下:

事务A先查询所有a>2的记录,只有5这一行

请添加图片描述
事务B插入值为0的行
请添加图片描述
事务A再次执行刚才的SQL语句,结果与之前的一致,满足可重复读。
请添加图片描述
事务A可以修改事务B插入的行记录
请添加图片描述
事务B提交后,事务A的update才可以继续执行
请添加图片描述请添加图片描述
事务A查询所有行数据,发现事务B插入的数据在事务A中显示出来了
请添加图片描述

由此,幻读的解决方式是得锁整个表了

如果对幻读还不明白,大家一定要开命令行自己试一试哦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值