能否将Phantom读入刚更新的某行?

时间:2019-01-20 13:26:45

标签: mysql transactions innodb repeatable-read

从MySQL词汇表:

  

phantom:在查询的结果集中出现的行,但在较早的查询的结果集中没有出现。例如,如果一个查询在一个事务中运行两次,同时,另一个事务将在插入新行或更新行以使其与查询的WHERE子句匹配之后提交。 >

粗体部分正确吗?如果有

CREATE TABLE  t1 (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `c1` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

隔离级别是REPEATABLE READ,我知道

mysql> start transaction;
mysql> SELECT * FROM t1 WHERE c1 < 10;
+----+------+
| id | c1   |
+----+------+
|  1 | 4    |
+----+------+
mysql> SELECT * FROM t1 WHERE c1 < 10;
+----+------+
| id | c1   |
+----+------+
|  1 | 4    |
+----+------+

即使没有人执行任何INSERT操作,而仅执行UPDATE操作,有时我也可能从以后的查询中获得不同的结果?我的MySQL版本是5.7。

SQL标准指示幻像读取仅与并发INSERT相关,尽管单词 generate 有点令人困惑。从ISO / IEC 9075:1992,数据库语言SQL- 1992年7月30日(第二次非正式审核草案):

  

P3(“幻影”​​):SQL事务T1读取满足某些搜索条件的行N的集合。然后,SQL事务T2执行SQL语句,该语句生成满足SQL事务T1使用的搜索条件的一个或多个行。如果SQL事务T1然后以相同的搜索条件重复初始读取,则它将获得不同的行集合。

2 个答案:

答案 0 :(得分:1)

InnoDB REPEATABLE-READ事务隔离级别可防止幻像行,但前提是您的SELECT查询是非锁定查询。

因此,您可以在事务期间多次使用相同的查询条件进行SELECT,即使在其他会话以可能影响您的方式插入,更新或删除行的情况下,也可以确保一次又一次获得相同的结果。结果集。开始新事务后,您的查询将立即看到对行进行的更改。

但是InnoDB有一个奇怪的情况:如果您像以下之一运行locking read query

SELECT * FROM t1 WHERE c1 < 10 FOR UPDATE

SELECT * FROM t1 WHERE c1 < 10 LOCK IN SHARE MODE

SELECT * FROM t1 WHERE c1 < 10 FOR SHARE -- MySQL 8.0 syntax

然后,SELECT将“查看”数据并发更改的结果,就像您的事务已作为READ-COMMITTED事务启动一样。

您甚至可以在同一个REPEATABLE-READ事务中的锁定读取查询和非锁定读取查询之间来回切换,并且每个查询都会看到不同的结果集。因此,如果使用锁定的SELECT语句,请注意这一点。

我认为您显示的摘录中的“生成”一词适用于INSERT或UPDATE。他们需要一个术语来适用于这两种情况,因为我想他们不想写更清晰的短语,例如“插入或更新”。

答案 1 :(得分:0)

据我所知,在事务中使用REPEATABLE READ时,不可能(应该吗?)获得幻像行。

在可重复读锁中创建事务时,一旦运行事务中的第一个查询,mysql就会创建数据的“快照”。

因此,任何select语句都将在该快照中获取数据。

据我所知,文档中的两个警告可能会导致意外结果:

  1. 内进行的任何读取查询都会影响以后的SELECT语句(这可能不是意外的,但我想可能会造成混乱)。
  2. 通过 other 事务对数据库进行的其他写查询会影响当前事务中在内部进行的写查询。

第2点有一个更令人困惑的地方-有关更多说明,请参见the note in the docs here。这还将详细介绍可重复读取隔离级别。

它看起来像InnoDB guards against phantom rows

  

为防止产生幻影,InnoDB使用称为“下一键锁定”的算法,该算法将索引行锁定与间隙锁定结合在一起。 InnoDB执行行级锁定的方式是,当它搜索或扫描表索引时,会在遇到的索引记录上设置共享或互斥锁。因此,行级锁实际上是索引记录锁。

     

Section 15.7.1, “InnoDB Locking”中所述,可以禁用间隙锁定。这可能会导致幻影问题,因为在禁用间隙锁定时,其他会话可以在间隙中插入新行。

我很想知道您是否有其他情况导致您遇到这种情况!链接的任何文档都澄清了吗?如果这是一个相当“深入”的mysql问题,也许DBA堆栈交换可能是一个更好的尝试。