3

MVCC数据库隔离模式是否允许正在进行的事务查看其他事务插入(和提交)的行?

例如,给定:

  • 桌子names[id BIGINT NOT NULL, name VARCHAR(30), PRIMARY KEY(id), UNIQUE(name)]
  • 交易 T1 和 T2,
T1: open transaction
T2: open transaction
T1: select * from names;
    insert into names(name) values("John");
    // do something
    commit;
T2: select * from names;
    insert into names values("John");
    // do something
    commit;

T2 什么时候第一次意识到新的行?到select时候?到insert时候?还是commit当时?

4

3 回答 3

2

不,它显示了数据库的快照。不会出现新行(幻读)。无论发生什么,快照都保持不变。

这通常通过使用时间戳标记插入的行来实现,并在读取时静默丢弃比事务开始时插入的行。

在您的示例中,T2 永远不会意识到新行,因为在提交后旧事务完成。只有新事务会看到插入的行(在本例中为“T3”)。

于 2012-12-02T23:52:32.507 回答
2

答案实际上取决于服务器实现以及唯一约束是否标记为可延迟。

我还没有为其他数据库测试过它,但是在 PostgreSQL(作为最杰出的开源 MVCC 数据库之一)中,在我的测试中复制你的设置 T2 失败了INSERT。但是,T2 无法看到 T1 通过使用 所做的任何更改SELECT

我在 2 个单独的 SQL 连接中几乎同时执行了以下语句:

BEGIN;
SELECT * FROM names;
SELECT pg_sleep(10);
INSERT INTO names values('john');
SELECT pg_sleep(10);
COMMIT;

一个成功,但另一个在 10 秒后失败:

ERROR:  duplicate key value violates unique constraint "names_pkey"
DETAIL:  Key (name)=(john) already exists.

这是有道理的,因为文档说:

如果一个尚未提交的事务插入了冲突的行,那么潜在的插入者必须等待以查看该事务是否提交。如果它回滚,则没有冲突。如果它在没有再次删除冲突行的情况下提交,则存在唯一性违规。

但是,如果唯一性约束被标记为可延迟,则将在 COMMIT 时检查唯一性:

如果唯一性约束是可延迟的,则存在额外的复杂性:我们需要能够为新行插入索引条目,但将任何违反唯一性的错误推迟到语句结束甚至更晚。

于 2012-12-03T00:33:03.960 回答
0

这取决于事务隔离级别;SQL 标准实际上为 MVCC 数据库指定了 4 个级别。它们是(按严格程度递增的顺序):

  • 阅读未提交- 本质上,根本没有隔离。这不是一个值得关注的有趣案例,但在这种情况下,T2 显然会在 SELECT 时间看到新行。
  • 读取已提交- 无法读取未提交的更新。这是 Postgres 的默认设置。在这种情况下,T2 将在 SELECT 时间看到新行,因为 T1 已经提交。
  • 可重复读取- 所有读取将永远不会看到其他并发更新[1],即使已提交。这是 Mysql+InnoDB 默认的。在这种情况下,T2 应该在 COMMIT 时间失败(带有序列化错误),尽管引擎可以提前知道 INSERT 不能成功并在 INSERT 时间提前失败,这取决于唯一性约束是否推迟到提交时间。
  • 可序列化- 类似于可重复读取,但事务必须在逻辑上表现得好像它们一个接一个地执行。在这种情况下,与可重复读取的行为相同。

这里有趣的观察是,在 Postgres 的默认事务隔离级别下,T2在提交后可以看到 T1 的更改。这对大多数人来说可能是违反直觉的。

(请注意,mvp 的复制似乎在 INSERT 时间失败,即使我说读取提交应该在 COMMIT 时间失败;这是因为他在 T1 的 COMMIT 语句之前交错了 T2 的 SELECT 语句,这不是问题中提出的交错。)

[1] 从技术上讲,该标准允许在此隔离级别进行幻读,其中可以看到最近提交的插入,但我所知道的没有 MVCC 实现实际上允许这样做。

于 2015-07-09T22:00:02.667 回答