PostgreSQL 的可重复读允许幻读 但它的文档说它不允许

fat*_*sal 6 postgresql

我对 Postgresql 可重复读取隔离级别有问题。我确实做了一个关于可重复读隔离级别在幻读发生时的行为的实验。

Postgresql 的手册说“该表还显示 PostgreSQL 的可重复读实现不允许幻读。”

但是出现了幻读;

CREATE TABLE public.testmodel
(
    id bigint NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

--第 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;
Run Code Online (Sandbox Code Playgroud)

--第二场--

BEGIN TRANSACTION ISOLATION LEVEL Repeatable Read;    
INSERT INTO TestModel(ID)
VALUES (10);

Select sum(ID)
From TestModel
where ID between 1 and 100;

COMMIT;
Run Code Online (Sandbox Code Playgroud)

我遵循的步骤;

  1. 创建表
  2. 运行会话 1(我评论了 commit 语句)
  3. 运行会话 2
  4. 在会话 1 中运行提交语句。

令我惊讶的是,它们(会话 1、会话 2)都正常工作,没有任何异常。

据我了解的文件。它不应该是。在会话 2 之后提交时,我期待会话 1 抛出异常。

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

Nic*_*nes 7

您引用的文档将“幻读”定义为以下情况:

事务重新执行查询,返回一组满足搜索条件的行,并发现满足条件的行集由于另一个最近提交的事务而发生了变化。

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

由于您在每个事务中只读取一次数据,因此这不能作为幻读的示例。它属于“序列化异常”的更一般类别,即如果事务被连续执行就不会发生的行为。这种类型的异常只能在SERIALIZABLE隔离级别避免。

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