MySQL 试图通过在对非索引列执行 Delete 语句时锁定整个 table 来阻止什么现象

What Phenomena does MySQL try to prevent by locking the whole table upon executing Delete statement with the condition on a non-indexed column

使用 Repea 的 MySQL 隔离级别table 读取。

给定 table test 具有非索引列 quantity:

id    |     quantity
--------------------
1     |      10
2     |      20
3     |      30

Tx1执行1st,注意还没有commit,意思是所有获取的锁还没有释放

Tx1:

START TRANSACTION;
DELETE FROM test WHERE quantity=10;

正在执行 Tx2

TX2:

START TRANSACTION;
INSERT INTO test(quantity) VALUES (40);
COMMIT;

对于 Tx2,我得到以下结果:

Lock wait timeout exceeded; try restarting transaction

我明白,由于 quantity 列没有索引,delete 语句进行完整的 table 扫描,锁定所有行(与 where 条件是否匹配)并且还在聚集索引中的最后一个索引记录之前和之后应用间隙锁,导致完全阻塞 table 因此来自 tx2 的 insert 语句无法获取锁要插入的一行。

来自MySQL manual(对于Repeatable读取隔离级别):

  • For a unique index with a unique search condition, InnoDB locks only the index record found, not the gap before it.

  • For other search conditions, InnoDB locks the index range scanned, using gap locks or next-key locks to block insertions by other sessions into the gaps covered by the range (this is used in my case).

考虑到应用任何给定隔离级别的锁定以防止 phenomenas 我有点困惑在这种情况下阻止整个 table 的原因是什么,我的意思是在这种情况下阻止整个 table 会阻止什么样的 phenomena

默认情况下,InnoDB 在 Repeatable Read 隔离级别使用一致的快照,这意味着您可以获得元组和范围的可重复读取。

即使 SQL 标准说 Phantom ReadsSerializable 阻止并且 Repeatable Read 可能不会阻止它。

有关间隙锁定工作原理的更多详细信息,请查看 this post written by Percona