简体   繁体   English

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

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

If during execution of transaction A, a concurrent transaction B adds a row that fits the search criteria of transaction A and commits, what will happen when transaction A commits?如果在事务 A 执行过程中,并发事务 B 添加了符合事务 A 搜索条件的行并提交,那么事务 A 提交时会发生什么? Will it include the new row, or will the transaction fail?它会包含新行,还是事务会失败?

Assuming they are run in Repeatable Read isolation level in Postgresql.假设它们在 Postgresql 中以可重复读隔离级别运行。

The transaction A won't fail .事务A不会失败 It won't see the data inserted by transaction B .它不会看到事务B插入的数据。

Demo:演示:

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

Transaction A :交易A

begin transaction isolation level repeatable read;

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

Transaction B :交易

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

Transaction A :交易A

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

No (4, 300) row.没有(4, 300)行。

(tested on PostgreSQL 11.2) (在 PostgreSQL 11.2 上测试过)

Note that PostgreSQL has stronger guarantees on REPEATABLE READ isolation level.请注意, PostgreSQLREPEATABLE READ隔离级别有更强的保证 It prevents phantom reads .它可以防止幻读

From the documentation :文档

The Repeatable Read isolation level only sees data committed before the transaction began;可重复读隔离级别只看到事务开始前提交的数据; it never sees either uncommitted data or changes committed during transaction execution by concurrent transactions.它永远不会看到未提交的数据或并发事务在事务执行期间提交的更改。 (However, the query does see the effects of previous updates executed within its own transaction, even though they are not yet committed.) This is a stronger guarantee than is required by the SQL standard for this isolation level (但是,查询确实会看到在其自己的事务中执行的先前更新的影响,即使它们尚未提交。)这是比 SQL 标准对此隔离级别所要求的更强的保证

From the Table 13.1.来自表 13.1。 Transaction Isolation Levels : 事务隔离级别

Phantom reads are allowed at REPEATABLE READ isolation level but not in PGREPEATABLE READ隔离级别允许幻读,但在 PG不允许

See also :另见

Update更新

If the statement如果声明

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

is issued as the last statement of transaction A only 2 rows will be updated because from the point of view of transaction A there are only two rows satisfying the balance >= 100 predicate:作为事务A的最后一条语句发出,只有 2 行将被更新,因为从事务A的角度来看,只有两行满足balance >= 100谓词:

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

After a commit:提交后:

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

Only rows returned by this仅由此返回的行

select * from accounts where balance >= 100;

statement are updated (excluding the row inserted by transaction B )语句被更新(不包括事务B插入的行)

Note the transaction A will fail if it tries to update a row changed by another committed concurrent transaction:请注意,如果事务A尝试update由另一个提交的并发事务更改的行,它将会失败

A一种

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

B

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

A :

-- 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

The error is expected.错误是预料之中的。 From the documentation:从文档:

If the first updater rolls back, then its effects are negated and the repeatable read transaction can proceed with updating the originally found row.如果第一个更新器回滚,那么它的影响就被否定了,可重复读取事务可以继续更新最初找到的行。 But if the first updater commits (and actually updated or deleted the row, not just locked it) then the repeatable read transaction will be rolled back with the message但是如果第一个更新程序提交(并且实际上更新或删除了该行,而不仅仅是锁定它)那么可重复读取事务将与消息一起回滚

ERROR: could not serialize access due to concurrent update because a repeatable read transaction cannot modify or lock rows changed by other transactions after the repeatable read transaction began. ERROR: could not serialize access due to concurrent update因为在可重复读事务开始后,可重复读事务无法修改或锁定由其他事务更改的行。

It is expected that applications will retry failed transactions:预计应用程序将重试失败的事务:

When an application receives this error message, it should abort the current transaction and retry the whole transaction from the beginning.当应用程序收到此错误消息时,它应该中止当前事务并从头开始重试整个事务。

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

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