暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

mysql 幻读实例

原创 aisql 2021-12-08
1174

在丁奇老师的《MySQL 实战 45 讲》 中第22讲 幻读是什么,幻读有什么问题? 这一讲中,给出了幻读的定义,以及存在的问题。

这里抄借几个过来:
幻读的定义:幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。
幻读的两个说明:
1、 在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。
2、 其它session修改结果,被 当前session select 语句用“当前读”看到,不能称为幻读。幻读仅专指“新插入的行”。

在网上搜到 big_cat这位大神 对幻读另外的一个说明
https://segmentfault.com/a/1190000016566788

幻读,并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。

理论基础大家可以结合两者一起看。

但丁奇老师的整篇操作的例子都是在当前session 用select * from t for update 主动的,强制的当前读来说明幻读。这里我有提到两个关键词“主动的,强制的”。 但我们实际业务中,常常是被动的当前读。
“主动的,强制的”当前读,就和RC一样了,我主动读取最新已提交版本,我认为就是自己业务接受两次读不一致了。

接下来我就用两个可复现的例子,来分别复现丁奇老师对幻读的定义和big_cat这位大神对幻读的定义。

第一个例子

丁奇老师定义的幻读 即另外session插入引起的幻读 但我这里的例子更符合实际 是我“被动的”当前读造成的幻读,我整个例子中,没有“主动的,强制的”当前读。

构造测试数据

DROP TABLE IF EXISTS new_table; create table if not exists new_table (idx int, name varchar(10), age int ) engine=InnoDB; insert into new_table(idx,name,age) values(3,'b',12)
复制

VVMWK5FR3JVB2QCL3~US.png

我先把T1…T5时刻读到的数据先贴出来

CAOW8T349TCSVY5DTPGL.png

我T1,T3,T4,T5是在同一个事务中,按照RR可重复读的定义,他们读出的数据该是一样的。但T5出现了不一样的数据,即出现了幻读。
且我没有“主动的,强制的”当前读。是什么原因造成的呢?我来们分析一下。

如果你按照我上图的顺序一一执行,当执行到 事务A update的时候,你看mysql 返回的提示
2 row(s) affected Rows matched: 2 Changed: 2 Warnings: 0

我明明在T4查询 只有一行啊。affected Rows和Changed都是2行呢。
因为在事务中,凡是写入语句都会强制的当前读。 即 update语句时,发生了当前读,修改了两行。

我给一下,我理解总结的,隔离级别下,究竟什么数据我能看见

RC: 语句执行时 能看到已提交的事务 和自己本身事务的修改
RR: 两种情况 以一致性视图来解决可重复读的问题
1、begin 开始的事务
第一个select 语句时产生一致性视图(此时已提交的事务和自己本身事务的修改)
后面的select 语句以第一次产生的一致性视图为准
2、start transaction with consistent snapshot 开始的事务
事务开始时即产生一致性视图 (此时已提交的事务和自己本身事务的修改)
后面的select 语句以第一次产生的一致性视图为准

且根据隔离级别定义,我自己事务修改的,就能看见。所以update触发当前读,修改了两行,所以在T5时刻,就能看见两行了,出现了丁奇老师的幻读的定义 幻读仅专指“新插入的行”。

第二个例子

big_cat 大神提到的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作

数据还是上面的数据

WRHGU6S~U6OH8JA1IU_T.png

T5时刻数据不看,因为它已不在事务A中了。 T1,T3,T4是在同一个事务中 且T4之前执行了删除 delete 强制触发了当前读 那么T4是不是该读到空行呢
是什么原因造成的呢?我来们分析一下

同样的,一句一句来执行,当执行事务A的delete 语句时,会提示 0 row(s) affected

因为受影响的行数为0 即这个delete操作数据库啥也没有做,所以即使是强制当前读了,但对当前的一致性视图没有产生任何影响。

那么T4时 读到的还是事务最初创建的一致性视图。

可能第二个例子不能算是幻读。但的确从事务A语义流程走下来。T4可能会觉得看不到。如果不算幻读 就当一个特例了解一下吧。

文档中提到的一致性视图,大家参见MVCC相关资料了解。

最后修改时间:2021-12-08 17:50:43
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论