深入理解MySQL幻读

众所周知,MySQL在InnoDB下有四种隔离级别:

读未提交

读已提交

可重复读

串行化

其中可重复读可以避免脏读和不可重复读。但是对于幻读(a事务在b事务insert提交前后,两次分别读到的数据不一致),却存在争议。

实验分析:

准备数据表

create table tb(
    id int not null primary key auto_increment,
    num int not null
);
insert into tb(id, num) values(1, 11), (2, 22), (3, 33);
select * from tb;

执行结果:

id num

1 11

2 22

3 33

查看隔离级别,将隔离级别调到RR。

set global transaction isolation level repeatable read;
select @@global.tx_isolation;
select @@tx_isolation;  -- 当前会话的隔离级别必须为RR

打开两个会话(隔离级别都要为RR)。按表格顺序执行。
1、
在这里插入图片描述
对于事务a读取结果:(在事务a内读到了新插入的行记录–phantom)
在这里插入图片描述
注:MySQL5.7和8.0都是这种执行结果。
begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作 InnoDB 表的语句,事务才真正启动。如果你想要马上启动一个事务,可以使用 start transaction with consistent snapshot 这个命令。第一种启动方式,一致性视图是在执行第一个快照读语句时创建的;第二种启动方式,一致性视图是在执行 start transaction with consistent snapshot 时创建的。
注:RR隔离级别下,事务启动的时候创建一个视图。只要本事务不对某一数据更新,那么每一次读到的数据是一样的。

2、还是基础数据表
在这里插入图片描述
实验结果:a事务的两次select查询到的结果相同,在后一次查询中没有返回新插入id=4的那条记录。
在这里插入图片描述
据此,很多人判断说RR隔离级别下“不存在”幻读。
但果真如此吗?
出现上面的试验结果,是因为在RR隔离级别事务下,Mysql会对前一次select的结果快照。所以第二次select其实是快照读(这也正是RR隔离级别下能够避免不可重复读的策略)。

3、基础数据表
在这里插入图片描述
实验结果:在a事务的第二次select中出现了b事务新插入的id=4的记录。
在这里插入图片描述
Ps:假如给第二次的select查询上锁(无论是共享锁还是排它锁),也会得到同样的结果,都会令快照失效。

参考:
https://www.jianshu.com/p/70477870d8f5
https://www.jianshu.com/p/4c02a3a2e9d2
极客时间45讲

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值