从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然后以相同的搜索条件重复初始读取,则它将获得不同的行集合。
答案 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语句都将在该快照中获取数据。
据我所知,文档中的两个警告可能会导致意外结果:
SELECT
语句(这可能不是意外的,但我想可能会造成混乱)。第2点有一个更令人困惑的地方-有关更多说明,请参见the note in the docs here。这还将详细介绍可重复读取隔离级别。
它看起来像InnoDB guards against phantom rows。
为防止产生幻影,InnoDB使用称为“下一键锁定”的算法,该算法将索引行锁定与间隙锁定结合在一起。 InnoDB执行行级锁定的方式是,当它搜索或扫描表索引时,会在遇到的索引记录上设置共享或互斥锁。因此,行级锁实际上是索引记录锁。
如Section 15.7.1, “InnoDB Locking”中所述,可以禁用间隙锁定。这可能会导致幻影问题,因为在禁用间隙锁定时,其他会话可以在间隙中插入新行。
我很想知道您是否有其他情况导致您遇到这种情况!链接的任何文档都澄清了吗?如果这是一个相当“深入”的mysql问题,也许DBA堆栈交换可能是一个更好的尝试。