为什么在MySQL中已经被另一个事务更新的行无法被更新。

25 浏览
0 Comments

为什么在MySQL中已经被另一个事务更新的行无法被更新。

我正在尝试理解MySQL InnoDB的可重复读隔离级别,但在尝试这两个事务时,它表现出我无法理解的行为。

以下是我对测试的初始化设置:

mysql> SHOW CREATE TABLE `test`;

+-------+---------------------------------------------------------------------------------------+

| 表名 | 创建表语句 |

+-------+---------------------------------------------------------------------------------------+

| test | CREATE TABLE `test` (

`ID` int(11) NOT NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |

+-------+---------------------------------------------------------------------------------------+

1行记录(0.00秒)

mysql> SELECT * FROM `test`;

+----+

| ID |

+----+

| 1 |

+----+

1行记录(0.00秒)

mysql> SELECT @@TX_ISOLATION;

+-----------------+

| @@TX_ISOLATION |

+-----------------+

| REPEATABLE-READ |

+-----------------+

1行记录, 1警告(0.00秒)

表格如下:

| 序号 | Tx1 | Tx2 |

|------|------------------------------|-------------------------------------------------------------|

| 1 | START TRANSACTION | START TRANSACTION |

| 2 | SELECT * FROM test; | SELECT * FROM test; |

| 3 | SELECT * FROM test WHERE ID = 1 FOR UPDATE; | |

| 4 | UPDATE test SET ID = 2 WHERE ID = 1; | UPDATE test SET ID = 3 WHERE ID = 1; # 需要等待锁 |

| 5 | SELECT * FROM test; | # 继续等待 |

| 6 | COMMIT; | |

| 7 | SELECT * FROM test; | SELECT * FROM test WHERE ID = 1; |

| 8 | | UPDATE test SET ID = 3 WHERE ID = 1; |

| 9 | SELECT * FROM test; | SELECT * FROM test; # 尽管行存在,但无法将1更新为3,仍返回2 |

| 10 | | UPDATE test SET ID = 3 WHERE ID = 2; |

| 11 | | COMMIT; |

| 12 | SELECT * FROM test; | SELECT * FROM test; |

我想知道MySQL在Tx2的第8行和第10行如何处理ID = 1和ID = 2。

如果我在Tx2的第4行使用"UPDATE test SET ID = 3 WHERE ID = 2",即使Tx1只持有ID = 1的独占锁,仍然需要等待锁吗?

0
0 Comments

为什么无法在MySQL中通过另一个事务已更新的行进行更新?

在第8步,没有锁定的记录,因为TX1已经执行了COMMIT,这清除了锁定。

也没有ID=1的记录,因为它已经被更新了。

在第9和第10步,由于REPEATABLE READ,Tx2无法更新记录。它无法“看到”id=2的记录,也找不到id=1的记录(因为它已经被删除/更改)。

只有在COMMIT之后,Tx2才能看到新的/更改的数据。

但是ID=1仍然可以通过select在Tx2中看到。如果我们可以选择它但不能更新它,这是很奇怪的。更新一个不可见的ID也很奇怪。

由于REPEATABLE READ,它仍然可见,请参考这个很好的解释为什么这些数据不能被更改。(注意:读取的数据不能被更改,但数据库中的数据可以!)

以上是出现此问题的原因和解决方法的整理。

0