MVCC数据库是否在事务中期看到插入的行?

时间:2012-12-02 21:33:52

标签: sql mvcc

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时间?

3 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:2)

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

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

我几乎同时在两个单独的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.

这是有道理的,因为documentation说:

  

如果尚未提交,则插入了冲突的行   事务,潜在的插件必须等待,看看是否   交易提交。如果它回滚,则没有冲突。如果它   提交时不再删除冲突的行,有一个   唯一性违规。

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

  

如果唯一约束是可延迟的,则还有其他约束   复杂性:我们需要能够为新行插入索引条目,   但推迟任何唯一性违规错误,直到声明结束或   甚至更晚。

答案 2 :(得分:0)

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

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

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

(注意mvp的再现似乎在INSERT时失败,即使我说read committed会在COMMIT时失败;这是因为他在T1的COMMIT之前交错了T2的SELECT语句声明,这不是问题中提出的交错。)

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