可重复读隔离级别 SELECT 与 UPDATE...WHERE

Fra*_*k J 5 mysql innodb transactions isolation-level

也许你可以在这里为我阐明一些事情:

数据库 = MySQL 5.7

存储引擎:InnoDB

隔离级别:可重复读

下表:

---------------
|   MyTable   |
---------------
| PK | Concur |
---------------
| 3  |   2    |
---------------
Run Code Online (Sandbox Code Playgroud)

我此时没有进行任何交易,我选择此记录,例如

SELECT * FROM MyTable WHERE PK = 3

并将结果存储在我的程序中。

我现在开始一个数据库事务。在我的事务开始后,外部进程Concur将 = 3 的记录从 2 增加到 3。PK

我还没有再次从我的交易中的该表中读取内容。

我从交易内部发出以下查询:

UPDATE MyTable SET Concur = 3 WHERE PK = 3 AND Concur = 2

这将成功0 records affected。很明显,它会根据我的交易开始后更改的数据进行评估。仍在交易中我随后查询:

SELECT * FROM MyTable WHERE PK = 3

这将返回记录,其中PK = 3 and Concur = 2包含交易之前的值。

为什么行为SELECTUPDATE ... WHERE行为不同,我错过了什么?

我本以为该UPDATE ... WHERE语句要么直接失败,而不是成功,影响 0 条记录,要么成功,影响 1 条记录,然后在之后崩溃COMMIT,但不是这种混合和匹配。

这里有什么见解吗?

Bil*_*win 6

https://dev.mysql.com/doc/refman/8.0/en/innodb-concient-read.html

一致读取意味着 InnoDB 使用多版本控制向查询提供数据库在某个时间点的快照。该查询会看到该时间点之前提交的事务所做的更改,而不会看到稍后或未提交的事务所做的更改。此规则的例外是查询会看到同一事务中较早语句所做的更改。此异常会导致以下异常:如果更新表中的某些行,则 SELECT 会看到更新行的最新版本,但它也可能会看到任何行的旧版本。如果其他会话同时更新同一个表,则异常意味着您可能会看到该表处于数据库中从未存在的状态。

重要的条件是,如果您更改行,您的一致读取将被“刷新”,因此它包括您刚刚所做的更改。

但是,如果您进行 UPDATE,则始终会更新该行的最新版本,而不是事务的一致性读取可以查看的版本。因此,如果另一个事务已经进行了该更改,则您的更新可能不会产生任何实际影响。这就是你观察到的情况。

因此,您的事务发出了更新,但没有更改该行。

这也许不是您希望 InnoDB 的行为方式,但它确实如此。