Mysql 是否可以对刚更新的行执行幻象读取?

Mysql 是否可以对刚更新的行执行幻象读取?,mysql,transactions,innodb,repeatable-read,Mysql,Transactions,Innodb,Repeatable Read,从MySQL词汇表: 幻影:出现在查询的结果集中,但不出现在先前查询的结果集中的行。例如,如果一个查询在一个事务中运行两次,同时,另一个事务在插入新行或更新行以使其与查询的WHERE子句匹配后提交 粗体部分正确吗?如果我有 CREATE TABLE t1 ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `c1` varchar(45) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; 隔离

从MySQL词汇表:

幻影:出现在查询的结果集中,但不出现在先前查询的结果集中的行。例如,如果一个查询在一个事务中运行两次,同时,另一个事务在插入新行或更新行以使其与查询的WHERE子句匹配后提交

粗体部分正确吗?如果我有

CREATE TABLE  t1 (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `c1` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
隔离级别是可重复读取的,我是这样做的

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    |
+----+------+
mysql>启动事务;
mysql>从t1中选择*其中c1<10;
+----+------+
|id | c1|
+----+------+
|  1 | 4    |
+----+------+
mysql>从t1中选择*其中c1<10;
+----+------+
|id | c1|
+----+------+
|  1 | 4    |
+----+------+
有时,即使没有人做任何插入,而只做更新,我也会从后面的查询中得到不同的结果?我的MySQL版本是5.7

SQL标准指出幻象读取仅与并发插入相关,尽管单词generate有点混乱。根据ISO/IEC 9075:1992,数据库语言SQL-1992年7月30日(第二次非正式审查草案):

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

据我所知,在使用可重复读取的事务中,不可能(不应该?)获得幻影行

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

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

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

  • 在事务中进行的任何读取查询都将影响未来的
    SELECT
    语句(这可能不是意外的,但我认为可能会造成混乱)
  • 其他事务对数据库进行的其他写入查询可能会影响在当前事务中进行的写入查询
  • 第二点是更令人困惑的一点——更多的解释请参见。本文还将详细介绍可重复读取隔离级别

    它看起来像InnoDB

    为了防止出现幻影,InnoDB使用了一种称为next key locking的算法,该算法将索引行锁定与间隙锁定相结合。InnoDB执行行级锁定的方式是,当它搜索或扫描表索引时,它会对遇到的索引记录设置共享或独占锁定。因此,行级锁实际上是索引记录锁

    如中所述,可以禁用间隙锁定。这可能会导致幻象问题,因为禁用间隙锁定时,其他会话可以将新行插入间隙


    我很想知道,在你的情况下,你是否有一个不同的环境造成了这种情况!链接的任何文档都澄清了这一点吗?如果这是一个相当“深入”的mysql问题,那么DBA堆栈交换可能是一个更好的尝试。

    InnoDB REPEATABLE-READ事务隔离级别可以防止虚行,但前提是SELECT查询是非锁定查询

    因此,您可以在一个事务期间多次使用相同的查询条件进行选择,并且可以保证一次又一次地获得相同的结果,即使其他会话正在以可能影响结果集的方式插入、更新或删除行。一旦您开始一个新的事务,您的查询就会看到同时对行所做的更改

    但InnoDB有一个奇怪的情况:如果您运行类似以下之一的:

    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
    
    从t1中选择*其中c1<10用于更新
    从t1中选择*其中c1<10锁定在共享模式下
    从t1中选择*其中c1<10表示SHARE--MySQL 8.0语法
    
    然后,SELECT将“查看”并发数据更改的结果,就好像您的事务已作为一个读提交事务启动一样

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


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

    这就是你要找的?答案是我的:)但从2011年开始。可能是因为我写了这篇文章后发生了一些变化。可以自由发表新的答案和评论。@Danielrera我还不能给你的文章写评论,但很容易在阅读提交级别上产生幻影行,因此文章的一部分肯定是错误的。此外,第二个投票最多的答案有一个关于可重复读取级别的幻影行的示例,尽管我不确定这些行是真正的幻影行还是它们被称为其他行。