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