【问题标题】:MySQL Repeatable Read isolation level and Lost Update phenomenaMySQL 可重复读隔离级别和丢失更新现象
【发布时间】:2019-05-02 22:09:03
【问题描述】:

High Performance Java Persistence book 的 6.3.3.3 部分中写道,丢失更新现象在 MySQL 可重复读取隔离级别中是可能的。这是截图:

假设如下(隔离级别为 REPEATABLE READ):

              tx1                     |                tx2
-----------------------------------------------------------------------------------
START TRANSACTION;                    |
SELECT * FROM test WHERE id = 1;      |
( say, DB_TRX_ID = 7 at this moment)   |
                                      |
                                      |  START TRANSACTION;
                                      |  SELECT * FROM test WHERE id = 1;
                                      |  UPDATE test SET name="x" WHERE id = 1;
                                      |  COMMIT;(say, makes DB_TRX_ID = 10)
                                      |
UPDATE test SET name="y" WHERE id = 1;|
COMMIT;

问题:

在 tx1 提交时,MVCC 是否会检测到行版本(DB_TRX_ID)不再等于 7(而不是 10)并执行回滚?还是提交成功导致更新丢失?

【问题讨论】:

  • MVCC 本质上是乐观的,因为查询会在实现中推进,直到发生提交冲突。但这并不意味着乐观锁定是相关的。你一直在问关于 MySQL 的问题,提到不恰当的锁定和其他错误的期望。不要问“不应该”——要给出答案,我们必须再写一个演示文稿——这太宽泛了,当你不理解它时,我们该怎么办?取而代之的是:准确地解释您认为根据特定演示文稿的理由会发生什么事情。然后我们可以告诉你你第一次出错的地方。
  • use text, not images/links, for text (including code, tables & ERDs)。使用链接/图像仅是为了方便补充文本和/或无法在文本中给出的内容。永远不要给出没有图例/键的图表。 PS 这里的意思是把表格作为文本给出。但是您还需要在帖子中提供我们回答问题所需知道的任何内容。因此,要么引用相关的内容(作为文本),要么复制不合法,然后改述。那么,关于泄漏的业务是什么?我们还需要从该链接中了解什么?
  • 我在哪里提到你说的锁定不当? tx1 选择一行,然后 tx2 更新并提交该行,然后 tx1 更新同一行并提交。所以我问在 tx1 提交时 MVCC 是否检查行版本是否已更新,因为他选择了行并进行回滚(称为乐观锁定),还是提交成功导致丢失更新?怎么了?
  • 请通过帖子编辑而非 cmets 进行澄清。 (解释所有您认为正在发生的步骤。)关于“我在哪里提到不恰当的锁定”:“MySQL MVCC 不应该使用数据库级别的乐观锁定来防止丢失更新”。

标签: mysql database relational-database repeatable-read


【解决方案1】:

根据 SQL 标准,Repeatable Read 应该防止:

  • 脏读
  • 不可重复读取

该标准没有提及丢失更新,因为该标准是在 2PL (Two-Phase Locking) 是事实上的并发控制机制时设计的。

如果您使用 2PL,那么可重复读取隔离级别确实会阻止 Lost Update

然而,MVCC 可以通过一个元组的多个版本提供可重复读取,但是,为了防止丢失更新,它们还需要事务调度程序来跟踪某个事务读取的记录的元组修改。显然,InnoDB 不是那样工作的。

MySQL MVCC 不应该使用数据库级悲观锁定来防止丢失更新导致事务回滚

MVCC 在可重复读取中不使用任何悲观锁定。唯一采用的锁是在聚集索引上采用的间隙锁和下一个键锁,但它们并不能防止丢失更新。

MySQL 仅对 Serializable 使用悲观锁定,它提供了 2PL 并发控制模型,即使在使用基于 MVCC 的 InnoDB 存储引擎时也是如此。

【讨论】:

  • 对不起,我应该在我的问题中写“乐观锁定”而不是“悲观锁定”。当 tx1 选择具有 MVCC 分配版本的行时,比如 X,然后 tx2 提交其更新,然后当 tx1 提交自己的更新时,我在想 MVCC 应该检测到行版本不再是 X 导致 tx1 回滚.因此,正如我从您的回答中了解到的那样,Innodb MVCC 在提交期间不会跟踪版本更改,因此 Innodb MVCC 没有提供乐观锁定,对吗?附:我已经更新了我的问题。您能否也更新您的答案?
  • 这只是一个实现细节。唯一标准化的就是那些需要防止的异常。因此,根据标准,它们的实施很好。它是如何真正在幕后工作的,不研究源代码就很难说清楚。
  • 更新时不需要检查行版本,但在提交之前加载的元组时需要检查。
  • 请在帖子中注明您是该书的作者。
  • 有道理:s/the/my
猜你喜欢
  • 1970-01-01
  • 2022-09-27
  • 2021-01-31
  • 2023-03-04
  • 1970-01-01
  • 2013-01-09
  • 1970-01-01
  • 2012-01-02
  • 2017-04-14
相关资源
最近更新 更多