使用可重复读的 MySQL 隔离级别。
给定表test
具有非索引列quantity
:
id | quantity
--------------------
1 | 10
2 | 20
3 | 30
Tx1执行第一个,注意它还没有提交,这意味着所有获取的锁还没有释放。
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 的语句无法获取要插入的行的锁。
来自 MySQLmanual https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html(对于可重复读隔离级别):
考虑到任何给定隔离级别中的锁定都用于防止phenomenas
我有点困惑在这种情况下阻止整个表的原因是什么,我的意思是什么样的phenomena
在这种情况下可以阻止整个表的阻塞吗?
默认情况下,InnoDB 使用一致快照Repeatable Read https://vladmihalcea.com/non-repeatable-read/隔离级别,这意味着您可以获得元组和范围的可重复读取。
即使 SQL 标准这么说Phantom Reads https://vladmihalcea.com/phantom-read/被阻止Serializable
然后Repeatable Read
可能无法阻止它。
有关间隙锁定如何工作的更多详细信息,请查看这篇文章由 Percona 撰写 https://www.percona.com/blog/2012/08/28/differences-between-read-committed-and-repeatable-read-transaction-isolation-levels/.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)