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