所谓的幻影当同一个查询在不同时间产生不同的行集时,事务中就会出现问题。例如,如果a选择
执行两次,但第二次返回第一次没有返回的行,行是”幻影”行。
假设有一个索引在id
的列孩子
表,并且你想读取并锁定表中标识符值大于100的所有行,目的是稍后更新所选行的某些列:
SELECT * FROM child WHERE id > 100 FOR UPDATE;
查询从第一个记录开始扫描索引id
大于100。让表包含行id
取值为90和102。如果在扫描范围内的索引记录上设置的锁没有锁定在间隙中所做的插入(在本例中是90到102之间的间隙),则另一个会话可以使用id
101股。如果你也这么做选择
在同一个事务中,您将看到一个带有id
101 (a)”幻影”)在查询返回的结果集中。如果我们将一组行视为一个数据项,那么新的虚子将违反事务隔离原则,即事务应该能够运行,以便它所读取的数据在事务期间不会更改。
为了防止幽灵,InnoDB
使用一种算法第二个关键锁定它结合了索引行锁定和间隙锁定。InnoDB
执行行级锁,在搜索或扫描表索引时,对遇到的索引记录设置共享锁或排他锁。因此,行级锁实际上是索引记录锁。此外,索引记录上的下一个键锁也会影响”差距”前指数记录。也就是说,下一个键锁是索引记录锁加上索引记录之前间隙上的间隙锁。如果一个会话记录上有共享锁或独占锁R
在索引中,另一个会话不能在紧接之前的间隙插入新的索引记录R
在索引顺序中。
当InnoDB
扫描一个索引,它还可以锁定索引中最后一条记录之后的空白。就像前面的例子中发生的那样:防止任何插入到表中的id
会比100大吗InnoDB
包括一个锁在空隙下面id
价值102。
您可以使用下一个键锁定在应用程序中实现唯一性检查:如果您以共享模式读取数据,并且没有看到将要插入的行的副本,那么您可以安全地插入行,并且知道在读取过程中在行的后继者上设置的下一个键锁定可以防止任何人同时为您的行插入副本。因此,下一个键锁定使您能够”锁”表中不存在的东西。
如中所述,可以禁用间隙锁定章节15.7.1,“InnoDB锁定”.这可能会导致幻影问题,因为当间隙锁定被禁用时,其他会话可以向间隙插入新行。