CodeGym /課程 /SQL SELF /巢狀交易:SAVEPOINT、ROLLBACK TO SAVEPOINT

巢狀交易:SAVEPOINT、ROLLBACK TO SAVEPOINT

SQL SELF
等級 53 , 課堂 0
開放

巢狀交易:SAVEPOINTROLLBACK TO SAVEPOINT

在 PostgreSQL 裡,沒有真正的巢狀交易(nested transactions)這種東西啦,只有外層交易,然後裡面可以有一堆 savepoint 的「層」。

所謂的「巢狀交易」在 PostgreSQL 通常就是指用 savepoint 這個機制,搭配 SAVEPOINTROLLBACK TO SAVEPOINTRELEASE SAVEPOINT 這幾個指令。這些不是獨立的交易,而是你在同一個外部交易裡設的 checkpoint,可以回到那個點,不用整個交易都回滾。

舉個生活例子:你在編輯器裡寫一大篇文章,偶爾會按 ctrl+s 存檔。如果你寫錯一堆,可以回到之前存的某個版本,不會整個進度都沒了。

管理 savepoint 的指令

要管理巢狀交易,PostgreSQL 給你三個主要指令:

SAVEPOINT

這個指令是用來建立「savepoint」,你之後可以回到這個點。它就像你交易裡的 checkpoint。

SAVEPOINT mypoint;

ROLLBACK TO SAVEPOINT

這個會回滾部分變更,就是從指定的 savepoint 之後的東西都撤銷,但更早的變更還會留著(都還在同一個外部交易裡)。

ROLLBACK TO SAVEPOINT mypoint;

RELEASE SAVEPOINT

這個是把 savepoint 刪掉,刪掉之後就不能再回到那個點了。

RELEASE SAVEPOINT mypoint;

範例:多表新增資料+可回滾

假設你在做一個訂單管理系統,要同時把資料存到兩個表:ordersorder_items。如果其中一個表新增失敗,不應該把另一個表的資料也撤銷。

BEGIN; -- 開始交易

-- 建立 savepoint
SAVEPOINT before_order;

-- 新增訂單到 orders 表
INSERT INTO orders (order_id, customer_id, date)
VALUES (1, 101, CURRENT_DATE);

-- 如果這裡出錯 — 回到這個 savepoint
SAVEPOINT before_order_items;

-- 新增商品到 order_items 表
INSERT INTO order_items (order_id, product_id, quantity)
VALUES (1, 2001, 4);

-- 如果有問題
-- ROLLBACK TO SAVEPOINT before_order_items;

-- 確認交易(commit 變更)
COMMIT;

如果你在新增 order_items 的時候出錯,可以回到 before_order_items,但 orders 表的變更還會保留。

實用建議跟常見錯誤

現在你已經知道 SAVEPOINTROLLBACK TO SAVEPOINT 怎麼用了,這裡有幾個小建議,讓你少踩雷:

  1. savepoint 名稱要清楚。 取 savepoint 名字時,建議用有意義又獨特的名稱,像 before_insertstep1 這種,debug 起來比較不會亂。
  2. 用完記得 release。 如果你確定不會再回到某個 savepoint,記得用 RELEASE SAVEPOINT 把它刪掉,不然交易裡會一堆垃圾。
  3. 巢狀交易 ≠ 獨立交易。 要記得,當你 COMMIT 之後,所有 savepoint 都沒了。外層 COMMIT 一下去,就不能再回滾囉。
  4. 資料鎖定。 就算你回到 savepoint,這個交易裡鎖住的資料還是會被鎖著。多人同時操作時要注意這點。

SAVEPOINTROLLBACK TO SAVEPOINT 這種巢狀交易技巧,對開發者來說超方便,能處理很多複雜情境。你可以把交易拆成多個階段,錯誤處理也更細緻,不用每次都整個回滾。記住,只要看到「回滾」這個詞,不用太緊張,有時候回滾反而是最好的解法啦!

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION