可重复读取隔离级别SELECT VS UPDATE…WHERE

本教程将介绍可重复读取隔离级别SELECT VS UPDATE...WHERE的处理方法,这篇教程是从别的地方看到的,然后加了一些国外程序员的疑问与解答,希望能对你有所帮助,好了,下面开始学习吧。

可重复读取隔离级别SELECT VS UPDATE...WHERE 教程 第1张

问题描述

也许你可以在这里为我解释一些事情:

DB=MySQL 5.7

存储引擎:InnoDB

隔离级别:可重复读取

下表:

---------------
|MyTable|
---------------
| PK | Concur |
---------------
| 3  |2 |
---------------

此时我没有正在进行的事务,我选择此记录,如下所示

SELECT * FROM MyTable WHERE PK = 3

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

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

我尚未再次从事务内的该表中读取。

我从我的事务内部发出以下查询:

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处失败,但不是这种混合和匹配。

这里有什么见解吗?

推荐答案

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

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

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

因此,您的事务发出了更新,但未行。

这可能不是您希望InnoDB的行为方式,但它确实是这样的。

好了关于可重复读取隔离级别SELECT VS UPDATE...WHERE的教程就到这里就结束了,希望趣模板源码网找到的这篇技术文章能帮助到大家,更多技术教程可以在站内搜索。