PostgreSQL的可重复读取允许幻像读取,但是其文档说不允许

时间:2019-04-04 13:00:10

标签: postgresql

我对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. 运行会话1(我评论了提交语句)
  3. 运行会话2
  4. 在会话1中运行commit语句。

令我惊讶的是,他们(会议1,会议2)都正常工作。

据我对文件的了解。不应该这样。 在会话2之后提交时,我期望会话1抛出异常。

这是什么原因?我很困惑。

2 个答案:

答案 0 :(得分:1)

您引用的docs在以下情况下定义了“幻读”:

  

事务重新执行查询,返回一组行   满足搜索条件并发现行集   满足条件已因另一个最近提交而发生更改   交易。

换句话说,如果您两次运行相同的查询(或两次查询相同数据的查询),则会发生幻像读取,并且得到不同的结果。 REPEATABLE READ隔离级别可防止这种情况的发生,即,如果您重复相同的已读,您将获得相同的答案。它不能保证这些结果中的任何一个都能反映数据库的当前状态。

由于在每个事务中仅读取一次数据,所以这不能成为幻像读取的示例。它属于“串行化异常”的更一般类别,即,如果按顺序执行事务,则不会发生的行为。仅在SERIALIZABLE隔离级别可以避免这种类型的异常。

Postgres Wiki上有一组 excellent 示例,描述了REPEATABLE READ允许但在SERIALIZABLE隔离下却可以阻止的异常:   https://wiki.postgresql.org/wiki/SSI

答案 1 :(得分:0)

您误解了“ 不允许幻像读取”的含义。

这仅表示幻像读取不会发生,而不是会出现错误。

在会话2的事务也被提交之前,会话2将看不到对该表的任何提交的更改。

repeatable read保证了事务期间数据库的一致状态,在该状态下,只有该事务本身所做的更改才可见,而其他更改则不可见。无需抛出错误。