在 MySQL 中,幻读的定义是什么?

2020-12-09 17:17:44 +08:00
 fantastM

一直没太完全明白幻读的定义,自己在 MySQL 手册也没找到幻读( Phantom Reads )的官方定义,另外我在另一篇帖子里 t/692386 也看到评论里对「可重复读隔离级别下是否解决了幻读问题」的回答不尽相同。因此就发个帖,想问一个权威的答案。

先说一下我对隔离级别的一些理解,如果有误,恳请各位指出。


快照读:读取 MVCC 快照中的数据。

当前读:读取数据库中最新的数据。SELECT … FOR SHARE 语句和 SELECT … FOR UPDATE 语句属于当前读,并且还有显式加锁的语义。

在 READ UNCOMMITTED 级别中,事务可以读取到其它事务中 尚未 提交的数据,这种问题被称为脏读。

在 READ COMMITTED 级别中,事务不可以读取到其它事务中 尚未 提交的数据,但是可以读取到其它事务中 已经 提交的数据,这种问题被称为不可重复读。

在 REPEATABLE READ 级别中,事务读取的是 MVCC 快照中的数据,因此事务中的 SELECT 语句是可重复读的。

READ COMMITTED 级别会使用记录锁,不会使用间隙锁和 next-key 锁。(从 MySQL 手册 Transaction Isolation Levels 中的「 InnoDB locks only index records, not the gaps before them 」这句话得知。)

REPEATABLE READ 级别中会使用记录锁、间隙锁和 next-key 锁( next-key 锁就是间隙锁 + 记录锁)。

假设使用 SELECT … FOR UPDATE 读取一段范围内的记录。

在 REPEATABLE READ 级别中的 SELECT 语句默认是 一致性非锁定读取,只会读取 MVCC 快照中的数据,不会读取到其它事务中的数据(不论是 尚未 提交或者是 已经 提交的)。但是,其它事务对数据库中数据的操作又是真实存在的,因此 REPEATABLE READ 级别的隔离性和数据库中数据的一致性是存在冲突的。这个时候 REPEATABLE READ 级别中的 SELECT 语句读取的快照数据不是最新的(解决这个问题的话,就是使用 锁定读取 或者升级隔离级别至 SERIALIZABLE ),可以将这个情况理解为此时 SELECT 语句读取了一个幻影数据,这就是所谓的幻读吗?

3021 次点击
所在节点    MySQL
9 条回复
xuanbg
2020-12-09 17:45:34 +08:00
在事务隔离的情况下,读到的数据不是期望的数据。
wps353
2020-12-09 17:58:34 +08:00
我是这么认为的,不知道对不对。
MySQL 的幻读和 SQL 标准的幻读有所差异。
MySQL 中幻读是针对当前读.
举个例子:
在 RC 级别下,user 表 id >=1 and id <=10 的数据现在只有 id=1 一条数据。这时候事务 A 执行 SQL(delete from user where id >=1 and id <=10),未 commit ; 如果此时事务 B 执行 SQL ( insert into user values(5)) 。这时候我们再提交事务 A,你会发现 user 里面居然还有一条 id=2 的记录,这和我们事务 A 执行的结果预期不符。
那么这个 id=2 的记录就属于幻读。
所以 MySQL 在 RR 级别下用 next-key 来保证例子中的事务 B 是插不进去的。
wps353
2020-12-09 17:59:44 +08:00
@wps353 应该是 insert into user values(2)
Takamine
2020-12-09 18:28:28 +08:00
我觉得是因为当前事务只是锁了当前所有符合的数据行当做快照,进行基于这个快照的处理,但是挡不住新增。
csl1995
2020-12-09 18:59:04 +08:00
幻读:同一个事务中,两次相同的查询取到的数据记录数不同。
不可重复读:同一事务中,两次相同的查询取到的数据记录不同。

幻读可以看作是一种特殊的不可重复读,幻读是数据数目增减,不可重复读是数据结果变化。

mysql 通过 MVCC(读快照)可以完全避免幻读的问题(5.7 版本可以,其他版本没验证过。规避幻读最主要的方式)
也可以通过加 next-key(空位置不允许插入)的方式避免幻读(比较少用)
littlewing
2020-12-09 19:39:03 +08:00
P3: r1[P]...w2[y in P]...((c1 or a1) [and (c2 or a2) any order)]

ref:
Berenson H, Bernstein P, Gray J, et al. A critique of ANSI SQL isolation levels[C]//ACM SIGMOD Record. ACM, 1995, 24(2): 1-10.
lewis89
2020-12-09 19:58:33 +08:00
@wps353 #2 不是间隙锁吗
wps353
2020-12-10 09:35:02 +08:00
@lewis89 next-key 是 gap lock 和 record lock 的结合体。
Flourite
2020-12-10 18:02:11 +08:00
看 mysql 的定义,前后两次读返回的数据不一致就叫做幻读

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/733829

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX