【发布时间】:2020-12-27 16:37:32
【问题描述】:
我正在尝试了解 MySQL InnoDB 的可重复读取隔离级别。但是当我尝试这 2 个事务时,它的行为是我无法理解的。
这是我的测试初始化
mysql> SHOW CREATE TABLE `test`;
+-------+---------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+---------------------------------------------------------------------------------------+
| test | CREATE TABLE `test` (
`ID` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+-------+---------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM `test`;
+----+
| ID |
+----+
| 1 |
+----+
1 row in set (0.00 sec)
mysql> SELECT @@TX_ISOLATION;
+-----------------+
| @@TX_ISOLATION |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
| No | Tx1 | Tx2 |
|---|---|---|
| 1 | START TRANSACTION | START TRANSACTION |
| 2 | SELECT * FROM test;# Return 1 |
SELECT * FROM test;# Return 1 |
| 3 | SELECT * FROM test WHERE ID = 1 FOR UPDATE;# return 1 |
|
| 4 | UPDATE test SET ID = 2 WHERE ID = 1; # OK |
UPDATE test SET ID = 3 WHERE ID = 1; # Lock wait |
| 5 | SELECT * FROM test;# Return 2 |
# Keep waiting |
| 6 | COMMIT; # OK | # Query OK: rows matched:0, changed: 0, warnings: 0 |
| 7 | SELECT * FROM test;# Return 2 |
SELECT * FROM test WHERE ID = 1;# Return 1 |
| 8 | UPDATE test SET ID = 3 WHERE ID = 1; #Query OK: rows matched:0, changed: 0, warnings: 0 |
|
| 9 | SELECT * FROM test;# Return 2 |
SELECT * FROM test;# Return 1 <-- cannot update 1 to 3 even the row exists |
| 10 | UPDATE test SET ID = 3 WHERE ID = 2;#Query OK: rows matched:1, changed: 1, warnings: 0 |
|
| 11 | COMMIT; #OK | |
| 12 | SELECT * FROM test# Return 3 |
SELECT * FROM test# Return 3 |
我想知道 MySQL 如何在第 8 行和第 10 行处理 Tx2 中的 ID=1 和 ID=2。
如果我在 Tx2 的第 4 行使用UPDATE test SET ID = 3 WHERE ID = 2,即使 Tx1 只持有 ID = 1 的排他锁,仍然需要锁定等待?
【问题讨论】:
-
ID不同时的锁等待可能是在等待间隙锁。
标签: mysql transactions innodb isolation-level