首页 > 解决方案 > Hibernate 和 PostgreSQL:REPEATABLE_READ 和使用@Version 注解来避免写入倾斜和其他现象

问题描述

我正在使用Isolation.REPEATABLE_READ在 Spring Boot 应用程序中复制大型实体图。它基本上执行 SELECT 和 INSERT。@Version我还在所有子实体上使用注释使用乐观锁定。我看到即使我在复制执行期间尝试更改实体图中的某些内容,后者也会继续进行,就好像什么都没发生一样。让我们假设从商业角度来看,这是可以接受的。根据 SQL-92 标准,可能发生的现象有:

另外四个(ANSI SQL 隔离级别的批评:https ://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-95-51.pdf ):

据我所知,在 PostgreSQL 上使用可重复读取,只有写入倾斜是可能的。但是使用乐观锁定,不会发生不一致。这个想法正确吗?

标签: postgresqlhibernatejpaspring-transactionsisolation-level

解决方案


在 PostgreSQL 上使用可重复读取,只有写入倾斜是可能的

正确的。

但是使用乐观锁定,不会发生不一致。

不,这是不正确的。您可以通过乐观锁定获得“写入偏差”:

CREATE TABLE worker (
   name text,
   on_duty boolean,
   version bigint DEFAULT 0
);

INSERT INTO worker (name, on_duty) VALUES
   ('alice', TRUE),
   ('bob', TRUE);

现在有两个事务在表上工作:

Transaction 1                             Transaction 2

BEGIN ISOLATION LEVEL REPEATABLE READ;

SELECT name, version FROM worker WHERE on_duty;

 name  │ version 
═══════╪═════════
 alice │       0
 bob   │       0
(2 rows)

                                          BEGIN ISOLATION LEVEL REPEATABLE READ;

                                          SELECT name, version FROM worker WHERE on_duty;

                                           name  │ version 
                                          ═══════╪═════════
                                           alice │       0
                                           bob   │       0
                                          (2 rows)

                                          UPDATE worker
                                          SET on_duty = FALSE, version = version + 1
                                          WHERE name = 'bob' AND version = 0;

                                          COMMIT;

UPDATE worker
SET on_duty = FALSE, version = version + 1
WHERE name = 'alice' AND version = 0;

COMMIT;

两个交易都成功了,但是你得到了写偏斜。


推荐阅读