繁体   English   中英

如果事务处于 Postgresql 中的可重复读隔离级别,事务是否会看到来自另一个并发事务的插入?

[英]Will a transaction see inserts from another concurrent transaction if they are in Repeatable Read isolation level in Postgresql?

如果在事务 A 执行过程中,并发事务 B 添加了符合事务 A 搜索条件的行并提交,那么事务 A 提交时会发生什么? 它会包含新行,还是事务会失败?

假设它们在 Postgresql 中以可重复读隔离级别运行。

事务A不会失败 它不会看到事务B插入的数据。

演示:

create table accounts (id bigserial primary key, balance bigint);
insert into accounts(balance) values (50), (100), (200);

交易A

begin transaction isolation level repeatable read;

select * from accounts where balance >= 100;
 id | balance 
----+---------
  2 |     100
  3 |     200
(2 rows)

交易

begin;
insert into accounts(balance) values (300);
INSERT 0 1
commit;

交易A

select * from accounts where balance >= 100;
 id | balance 
----+---------
  2 |     100
  3 |     200
(2 rows)

没有(4, 300)行。

(在 PostgreSQL 11.2 上测试过)

请注意, PostgreSQLREPEATABLE READ隔离级别有更强的保证 它可以防止幻读

文档

可重复读隔离级别只看到事务开始前提交的数据; 它永远不会看到未提交的数据或并发事务在事务执行期间提交的更改。 (但是,查询确实会看到在其自己的事务中执行的先前更新的影响,即使它们尚未提交。)这是比 SQL 标准对此隔离级别所要求的更强的保证

来自表 13.1。 事务隔离级别

REPEATABLE READ隔离级别允许幻读,但在 PG不允许

另见

更新

如果声明

update accounts set balance = balance + 30 where balance >= 100;

作为事务A的最后一条语句发出,只有 2 行将被更新,因为从事务A的角度来看,只有两行满足balance >= 100谓词:

update accounts set balance = balance + 30 where balance >= 100;
UPDATE 2

提交后:

commit;
COMMIT
select * from accounts;
 id | balance 
----+---------
  1 |      50
  4 |     300
  2 |     130
  3 |     230
(4 rows)

仅由此返回的行

select * from accounts where balance >= 100;

语句被更新(不包括事务B插入的行)

请注意,如果事务A尝试update由另一个提交的并发事务更改的行,它将会失败

一种

begin transaction isolation level repeatable read;
BEGIN
select * from accounts where id = 1;
 id | balance 
----+---------
  1 |      50
(1 row)

begin;
BEGIN
update accounts set balance = balance + 10;
UPDATE 3
commit;

-- By some logic based on the fact that the balance is 50 we decided to update it to 60
-- balance is updated by committed concurrent transaction 
update accounts set balance = 60 where id = 1;
ERROR:  could not serialize access due to concurrent update

错误是预料之中的。 从文档:

如果第一个更新器回滚,那么它的影响就被否定了,可重复读取事务可以继续更新最初找到的行。 但是如果第一个更新程序提交(并且实际上更新或删除了该行,而不仅仅是锁定它)那么可重复读取事务将与消息一起回滚

ERROR: could not serialize access due to concurrent update因为在可重复读事务开始后,可重复读事务无法修改或锁定由其他事务更改的行。

预计应用程序将重试失败的事务:

当应用程序收到此错误消息时,它应该中止当前事务并从头开始重试整个事务。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM