在透過 CALL
命令呼叫的儲存過程以及匿名程式碼塊(DO
命令)中,可以使用 COMMIT
和 ROLLBACK
命令結束事務。當使用這些命令結束事務後,會自動啟動一個新的事務,因此沒有單獨的 START TRANSACTION
命令。(請注意,BEGIN
和 END
在 PL/pgSQL 中有不同的含義。)
以下是一個簡單的例子
CREATE PROCEDURE transaction_test1() LANGUAGE plpgsql AS $$ BEGIN FOR i IN 0..9 LOOP INSERT INTO test1 (a) VALUES (i); IF i % 2 = 0 THEN COMMIT; ELSE ROLLBACK; END IF; END LOOP; END; $$; CALL transaction_test1();
新事務會以預設的事務特性(如事務隔離級別)開始。在迴圈提交事務的情況下,可能會希望新事務自動以與前一個事務相同的特性開始。 COMMIT AND CHAIN
和 ROLLBACK AND CHAIN
命令可以實現這一點。
事務控制僅在頂層呼叫的 CALL
或 DO
呼叫中,或者在沒有其他中間命令的巢狀 CALL
或 DO
呼叫中才可能。例如,如果呼叫棧是 CALL proc1()
→ CALL proc2()
→ CALL proc3()
,那麼第二個和第三個儲存過程可以執行事務控制操作。但是,如果呼叫棧是 CALL proc1()
→ SELECT func2()
→ CALL proc3()
,那麼最後一個儲存過程不能執行事務控制,因為中間有一個 SELECT
。
PL/pgSQL 不支援儲存點(SAVEPOINT
/ROLLBACK TO SAVEPOINT
/RELEASE SAVEPOINT
命令)。儲存點的典型使用模式可以用帶有異常處理器的塊來替代(請參閱 第 41.6.8 節)。在底層,帶有異常處理器的塊會形成一個子事務,這意味著在這樣的塊內部不能結束事務。
遊標迴圈需要特別考慮。請看這個例子
CREATE PROCEDURE transaction_test2() LANGUAGE plpgsql AS $$ DECLARE r RECORD; BEGIN FOR r IN SELECT * FROM test2 ORDER BY x LOOP INSERT INTO test1 (a) VALUES (r.x); COMMIT; END LOOP; END; $$; CALL transaction_test2();
通常,遊標在事務提交時會自動關閉。然而,像這樣在迴圈中建立的遊標會在第一次 COMMIT
或 ROLLBACK
時自動轉換為可保持遊標。這意味著遊標在第一次 COMMIT
或 ROLLBACK
時會被完全求值,而不是逐行求值。遊標仍然會在迴圈結束後自動刪除,因此這對使用者來說基本是不可見的。但必須記住,遊標查詢所獲取的任何表或行的鎖將在第一次 COMMIT
或 ROLLBACK
後不再被持有。
在由非只讀命令驅動的遊標迴圈中不允許使用事務命令(例如 UPDATE ... RETURNING
)。
如果您在文件中發現任何不正確、與您對特定功能的體驗不符或需要進一步澄清的內容,請使用此表單報告文件問題。