Postgresql

Postgres 40001 異常條件插入

  • October 20, 2019

我有 3 張桌子ABCactOnABC(i)一個對錶進行只讀操作的函式:

IF actOnABC(i) = 0 THEN
   RAISE EXCEPTION 'Message';
ELSE
   INSERT INTO TABLE B VALUES(...);
END IF;

我使用 Spring JDBC 執行它,事務隔離級別設置為 SERIALIZABLE。

隨著並發事務的負載/數量增加,我收到帶有消息的異常:

錯誤:由於事務之間的讀/寫依賴關係,無法序列化訪問。

可以說,我有兩個並發的 TransactionsT1T2. T1 and T2兩者都試圖插入。如果說,T1成功地將插入先插入到 table 中B,那麼可能actOnABC(i)已經評估過的結果T2可能會改變。因此T2會拋出異常。

我對情況的理解正確嗎?另外,有什麼方法可以將actOnABC(i)呼叫與INSERT語句結合起來以避免這種競爭條件?我確實考慮過使用事務級鎖。但恐怕這行不通,因為我有其他儲存過程正在積極更新表AB並且C.

有沒有更聰明的方法來處理這種情況?

編輯:有關儲存過程的更多資訊actOnABC()。此過程返回一個整數,其計算如下。

SELECT count(*) into tmp_a from (... access tables..);
SELECT count(*) into tmp_b from (... access tables...);
return tmp_a - tmp_b;

請參閱PostgreSQL 文件,第 13 章。並發控制,13.2。可重複讀取和可序列化隔離級別描述的事務隔離:

由於序列化失敗,使用此級別的應用程序必須準備好重試事務。

在 Postgres 函式中是不可能的——客戶端應用程序需要重試。在 Serializable 隔離級別中,即使是只讀事務也需要重試。

你應該可以把它放到一個INSERT INTO .. SELECT

INSERT INTO b (a,b,c)
 SELECT a,b,c
 FROM ( VALUES
   (...)
 ) AS t(a,b,c)
 WHERE actOnABC(i) = 0;

引用自:https://dba.stackexchange.com/questions/167505