Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

17.7.4 幽灵行

所谓的 幽灵 问题发生在事务中,当同一个查询在不同的时间产生不同的行集时。例如,如果一个 SELECT 语句执行两次,但第二次返回了一行第一次没有返回的行,这行就是一个 幽灵 行。

假设在 child 表的 id 列上有一个索引,并且您想读取和锁定所有 id 值大于 100 的行,以便稍后更新这些行的某些列:

SELECT * FROM child WHERE id > 100 FOR UPDATE;

查询扫描从 id 值大于 100 的第一条记录开始的索引。假设表中包含 id 值为 90 和 102 的行。如果锁定索引记录的范围不锁定插入到间隙中的记录(在本例中是 90 和 102 之间的间隙),那么另一个会话可以在表中插入一行新的记录,id 值为 101。如果您在同一个事务中执行相同的 SELECT 语句,您将在结果集中看到一行新的记录,id 值为 101(一个 幽灵)。如果我们将一组行视为一个数据项,那么这个新的幽灵子记录将违反事务的隔离原则,即事务应该能够运行,使得它读取的数据不在事务期间更改。

为了防止幽灵,InnoDB 使用一种称为 next-key 锁定 的算法,该算法将索引行锁定与间隙锁定结合起来。InnoDB 执行行级锁定,以便在扫描或搜索表索引时,设置共享或排他锁定在索引记录上。因此,行级锁定实际上是索引记录锁定。此外,next-key 锁定在索引记录上也影响了索引记录前的 间隙。也就是说,next-key 锁定是一个索引记录锁定加上索引记录前的间隙锁定。如果一个会话在索引记录 R 上拥有共享或排他锁定,另一个会话不能在索引顺序中 R 之前的间隙中插入新的索引记录。

当 InnoDB 扫描索引时,也可以锁定索引中的最后一条记录后的间隙。正如前面的示例所示:为了防止任何插入到表中 id 值大于 100 的记录,InnoDB 设置的锁定包括锁定 id 值 102 之后的间隙。

您可以使用 next-key 锁定来实现应用程序中的唯一性检查:如果您以共享模式读取数据,并且没有看到要插入的行的副本,那么您可以安全地插入行,并且知道 next-key 锁定在您的行的后继记录上设置的锁定,防止其他人同时插入副本。因此,next-key 锁定使您能够 锁定 表中的不存在项。

可以禁用间隙锁定,如 第 17.7.1 节,“InnoDB 锁定” 中所讨论的那样。这可能会导致幽灵问题,因为其他会话可以在禁用间隙锁定时插入新的行到间隙中。