MVCC数据库隔离模式是否允许正在进行的事务查看其他事务插入(和提交)的行?
例如,给定:
names[id BIGINT NOT NULL, name VARCHAR(30), PRIMARY KEY(id), UNIQUE(name)]
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
时间?
答案 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个级别。它们(按照严格程度的提高):
这里有趣的观察是,在Postgres的默认事务隔离级别,T2 可以在提交后查看T1的更改。这对大多数人来说可能是违反直觉的。
(注意mvp的再现似乎在INSERT时失败,即使我说read committed会在COMMIT时失败;这是因为他在T1的COMMIT之前交错了T2的SELECT语句声明,这不是问题中提出的交错。)
[1]从技术上讲,该标准允许在此隔离级别进行幻像读取,其中可以看到最近提交的插入,但我知道实际上没有实现MVCC实现。