【问题标题】:Visible from another transaction after update, is it a bug in MySQL MVCC?更新后从另一个事务中可见,这是 MySQL MVCC 中的错误吗?
【发布时间】:2020-04-13 21:47:21
【问题描述】:

这是我的情况:

CREATE TABLE test (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, value INT DEFAULT 0);
INSERT INTO test (id, value) VALUES (1, 10);

会话 A

START TRANSACTION;
SELECT value FROM test WHERE id = 1;
  10

会话 B

START TRANSACTION;
SELECT value FROM test WHERE id = 1;
  10

会话 A

UPDATE test SET value = value + 2 WHERE id = 1;
SELECT value FROM test WHERE id = 1;
  12
COMMIT;

会话 B

SELECT value FROM test WHERE id = 1;
  10

在这里我得到了预期的结果,因为 Session B 有行 id = 1 的独立副本,即来自 Session A 的提交是 NOT 在这里可见。

但是当我更新这一行时,隔离就会中断:

会话 B

UPDATE test SET value = value + 3 WHERE id = 1;

根据此视频https://www.youtube.com/watch?v=sxabCqWsFHg 关于 MVCC(15'00),此更新应被拒绝。但是 MySQL 接受了这个更新。

会话 B

SELECT value FROM test WHERE id = 1;
  15

所以这个选择得到了一个意想不到的结果:来自 Session A 的提交在 Session B 中是可见的。

我的MySQL版本是5.7.26,隔离级别是REPEATABLE-READ。

=== 更新 ===

此案例在带有 RocksDB 引擎的 MariaDB 10.4.10 中按预期工作。

会话 B

UPDATE test SET value = value + 3 WHERE id = 1;

返回

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction (snapshot conflict)

【问题讨论】:

    标签: mysql innodb isolation-level rocksdb mvcc


    【解决方案1】:

    在 InnoDB 中,锁定语句不遵守 REPEATABLE-READ 隔离。

    锁总是影响最近提交的行版本。所以它们的行为就像你使用了 READ-COMMITTED。

    这会影响UPDATEDELETE,以及锁定读取,例如SELECT...FOR UPDATE

    但是一旦你更新了一行,新版本就会在你的事务中可见。

    【讨论】:

    • 似乎REPEATABLE-READ 不适用于这种“可重复写入”场景。我将隔离级别更改为SERIALIZABLE 并按预期工作:MVCC 似乎未启用并且行已锁定。
    猜你喜欢
    • 2020-11-27
    • 2018-12-15
    • 2022-12-16
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多