InnoDB 锁定行而不是表
在这里,我使用带有此示例数据结构的 IntelliJ 控制台创建了一个包含 3 个会话的简单测试用例。
引擎:InnoDB(请注意,我在这里只谈论 InnoDB,我确信不同的引擎是不同的)
Mysql版本:8.0.25
DROP TABLE IF EXISTS `locktest`;
CREATE TABLE locktest
(
id INT UNIQUE KEY,
val INT
);
DROP TABLE IF EXISTS `dataTest`;
CREATE TABLE `dataTest`
(
id INT UNIQUE KEY,
val INT
);
INSERT INTO dataTest
VALUES (1, 1),
(2, 2),
(3, 3),
(4, 4);
现在在会话 1:
START TRANSACTION;
UPDATE dataTest
SET val = 100
WHERE id = 2;
所以现在它正在使用第 2 行并且尚未提交。
然后在第 2 节中:
START TRANSACTION;
INSERT INTO locktest
SELECT id, val from dataTest
WHERE id in (1,2);
正如预期的那样,这不会立即成功,因为它正在等待来自dataTest 的第 2 行的锁定。你可以在这里看到它正在等待:
但它已经成功地将id为1的行插入locktest。我们怎么知道呢?看Session 3
然后在第 3 节:
START TRANSACTION;
INSERT INTO locktest VALUES (10, 200);
INSERT INTO locktest VALUES (1, 200);
这里显示插入 id 为 10 的行发生得很快,但它必须等待下一次插入到locktest,因为在会话 2 中我们插入了一个 id 为 1 的行并且该会话尚未完成。
我们得出的结论是 MySQL 没有完全锁定表 locktest,只锁定 id 为 1 的行(因为 id 是唯一的),它允许插入 id 为 10 的行。
另外,请阅读this 和旁注,注意Gap Locks。