我对Postgresql可重复读取隔离级别有问题。 我确实做了一次有关可重复读取隔离级别行为的实验 幻像读取。
Postgresql的manual says“该表还显示PostgreSQL的Repeatable Read实现不允许幻像读取。”
但是幻影发生了;
CREATE TABLE public.testmodel
(
id bigint NOT NULL
);
-会话1-
BEGIN TRANSACTION ISOLATION LEVEL Repeatable Read;
INSERT INTO TestModel(ID)
VALUES (10);
Select sum(ID)
From TestModel
where ID between 1 and 100;
--COMMIT;
-会话2-
BEGIN TRANSACTION ISOLATION LEVEL Repeatable Read;
INSERT INTO TestModel(ID)
VALUES (10);
Select sum(ID)
From TestModel
where ID between 1 and 100;
COMMIT;
我遵循的步骤;
令我惊讶的是,他们(会议1,会议2)都正常工作。
据我对文件的了解。不应该这样。 在会话2之后提交时,我期望会话1抛出异常。
这是什么原因?我很困惑。
答案 0 :(得分:1)
您引用的docs在以下情况下定义了“幻读”:
事务重新执行查询,返回一组行 满足搜索条件并发现行集 满足条件已因另一个最近提交而发生更改 交易。
换句话说,如果您两次运行相同的查询(或两次查询相同数据的查询),则会发生幻像读取,并且得到不同的结果。 REPEATABLE READ
隔离级别可防止这种情况的发生,即,如果您重复相同的已读,您将获得相同的答案。它不能保证这些结果中的任何一个都能反映数据库的当前状态。
由于在每个事务中仅读取一次数据,所以这不能成为幻像读取的示例。它属于“串行化异常”的更一般类别,即,如果按顺序执行事务,则不会发生的行为。仅在SERIALIZABLE
隔离级别可以避免这种类型的异常。
Postgres Wiki上有一组 excellent 示例,描述了REPEATABLE READ
允许但在SERIALIZABLE
隔离下却可以阻止的异常:
https://wiki.postgresql.org/wiki/SSI
答案 1 :(得分:0)
您误解了“ 不允许幻像读取”的含义。
这仅表示幻像读取不会发生,而不是会出现错误。
在会话2的事务也被提交之前,会话2将看不到对该表的任何提交的更改。
repeatable read
保证了事务期间数据库的一致状态,在该状态下,只有该事务本身所做的更改才可见,而其他更改则不可见。无需抛出错误。