Watch at Ease看見世界,讀懂生活。

科技 · 實用指南

PostgreSQL 顯示「目前交易已中止」?重試前先找出第一個錯誤

把 SQLSTATE 25P02 視為先前失敗留下的狀態:先保存第一個 SQLSTATE,確認連線與交易邊界,再選擇完整復原或回到風險操作前已存在的儲存點。

一次資料庫操作失敗後,後續操作遭中止交易狀態阻擋的原創插畫。
原創插畫:後續 25P02 是結果;恢復前先保存第一個失敗。 Watch at Ease

PostgreSQL 的「目前交易已中止」通常不是根因,而是同一交易中較早陳述式失敗後的結果。反覆執行最後一條命令無法修復交易,也可能遮住第一個錯誤。

安全順序是先保留首錯證據,將它對應到正確連線與交易擁有者,再選擇有效的恢復分支,最後驗證連線後才重試或歸還連線池。

恢復前凍結第一個失敗

25P02 表示同一交易裡較早的陳述式失敗,PostgreSQL 會忽略後續命令直到交易恢復。先保存最早的伺服器錯誤、SQLSTATE、安全的陳述式指紋、參數類型、時間與呼叫堆疊。

若第一個可見訊息已是 25P02,就擴大日誌時間窗,檢查同一連線較早的客戶端自動陳述式、觸發器、限制錯誤與例外。

證明連線與交易邊界

記錄應用程式實例、連線池、連線識別、資料庫使用者、後端程序 ID、自動提交設定與交易開始時間。

找出誰開啟交易:BEGIN、ORM 工作單元、遷移框架、筆記本、資料庫客戶端,或驅動程式的隱含交易。Psycopg 預設連 SELECT 都會啟動交易。

沒有安全儲存點就完整復原

若可放棄本次交易,呼叫驅動或框架的 rollback,並確認連線離開失敗狀態後再重試。失敗連線未清理就回到池中,會把一個請求的問題傳給下一個請求。

完整復原會撤銷所有未提交變更。互動修復或遷移前,先記錄將失去的工作與交易擁有者;不要用 COMMIT 隱藏錯誤。

儲存點必須早於風險操作

只有失敗前已建立的儲存點能保留更早工作。先 ROLLBACK TO SAVEPOINT,讓交易恢復可用,再決定繼續或釋放;看到 25P02 後才建立已太晚。

交易仍中止時不能 RELEASE SAVEPOINT。若儲存點由框架管理,請用其交易 API,避免客戶端與伺服器狀態不同步。

稽核池、ORM 與客戶端隱藏陳述式

檢查健康探測、列數查詢、資料描述查詢、回呼或自動 flush 是否先於畫面所示 SQL 執行。DBeaver 議題只證明這種需求分支存在,不是你所用客戶端有相同缺陷的證據。

連線歸還前要明確提交或復原並確認空閒狀態;ORM 要保存被包裝前的首個資料庫例外。

重試工作單元,不只最後陳述式

先修正首錯,再從定義好的邊界重試最小且冪等的業務單元。只重試最後一個 INSERT 或 SELECT,可能重複資料庫外副作用。

依首個 SQLSTATE 分類可重試性:限制錯誤要修資料,暫時並行錯誤可有限次重試,權限錯誤要改設定。

回到服務前驗證連線

透過相同框架路徑執行無害檢查,確認下一交易正常開始與結束,並查看池重置日誌或連線狀態。

結案記錄首個 SQLSTATE、交易擁有者、連線身分、恢復分支、遺失工作、重試決定與預防措施。

比較完整復原與返回先前儲存點兩種恢復路徑的原創插畫。
原創插畫:只有儲存點早於風險操作且符合交易擁有者預期時,才能使用該分支。 Watch at Ease