mysql - MySQL 尝试通过在非索引列上执行 Delete 语句时锁定整个表来防止什么现象

标签 mysql database locking relational-database database-administration

使用 MySQL 隔离级别 Repeatable Read。

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

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

Tx1 执行 1st,注意它还没有提交,意味着所有获取的锁还没有释放。

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语句进行全表扫描,锁定所有行(无论 where 条件匹配与否),并且还在聚集索引中的最后一个索引记录之前和之后应用间隙锁,从而导致完全阻塞的表insert来自 tx2 的语句无法为要插入的行获取锁。

来自 MySQL manual (对于可重复读取隔离级别):

  • 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我有点困惑在这种情况下阻止整个表的原因是什么,我的意思是什么样的 phenomena在这种情况下阻止整个表被阻止?

最佳答案

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

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

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

关于mysql - MySQL 尝试通过在非索引列上执行 Delete 语句时锁定整个表来防止什么现象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53452571/

相关文章:

java - BlockingQueue 对于所有线程来说始终都是一样的吗?

java - 检查 ReentrantReadWriteLock 的状态(锁定读/写,线程等待)

mysql - 如何在同一查询mysql中选择组成员数和关注状态

mysql - 我需要一个好的MySQL数据库结构

c# - 如何测试锁内等待线程

python - 如何使用python将表单数据插入MYSQL

sql-server - 像 '%[9-15]%'(SQL 服务器)

java - 已连接到 MySQL 服务器,但未列出/显示任何表

php - 灵活的 PHP/MySQL 分页

java - 为什么插入语句的时间成本范围如此之大?