CodeGym /課程 /SQL SELF /SAVEPOINT 控制交易中的部分回滾

SAVEPOINT 控制交易中的部分回滾

SQL SELF
等級 39 , 課堂 2
開放

想像一下你在寫一本書。但很衰的是:事情不總是照計劃走。有時你寫了一整章,結果重看時發現第 5 段超爛。你會怎麼辦?你不會直接把整章丟掉吧?通常你只會改掉那些你覺得怪怪的地方。

SAVEPOINT 在 PostgreSQL 裡的用法就很像這樣。它讓你可以:

  1. 在交易裡設置保存點——就像在書裡放書籤一樣。
  2. 回到這些保存點,只取消從那時候開始的部分操作,不用把整個交易都回滾。
  3. 繼續處理剩下的資料,不用重來一次。

SAVEPOINT 的基本語法

SAVEPOINT 有關的指令其實很簡單。這裡是基本組合:

建立保存點(SAVEPOINT

SAVEPOINT savepoint_name;

這就像你說:「先記住這裡,搞不好等等要回來。」

回滾到保存點(ROLLBACK TO SAVEPOINT
ROLLBACK TO SAVEPOINT savepoint_name;

如果哪裡出包了,你就可以回到指定的 SAVEPOINT,把從那時候開始的變更都取消掉。

刪除保存點(RELEASE SAVEPOINT
RELEASE SAVEPOINT savepoint_name;

這會把你設的「書籤」移除。之後你就不能再回到這個點了。

簡單範例:網路商店購物

假設我們在經營一個網路商店。客戶把幾個商品加進購物車,我們想要做一個交易,裡面包含下單跟更新庫存表。但如果其中一個步驟失敗,我們只想取消那部分,而不是全部都重來。

BEGIN;

-- 步驟 1: 預留商品「SQL 書」
UPDATE inventory SET stock = stock - 1 WHERE product_id = 101;

-- 設置保存點
SAVEPOINT book_reserved;

-- 步驟 2: 預留商品「PostgreSQL 馬克杯」
UPDATE inventory SET stock = stock - 1 WHERE product_id = 102;

-- 哎呀,發現庫存沒有馬克杯!
ROLLBACK TO SAVEPOINT book_reserved;

-- 只對書的變更做提交
COMMIT;

這個例子發生了什麼?

  1. 我們用 BEGIN 開始了一個交易。
  2. 預留書之後設了一個保存點 book_reserved。這是我們的第一個「checkpoint」。
  3. 試著預留馬克杯,但出錯了(比如庫存不足)。
  4. 我們回到 book_reserved,只取消跟馬克杯有關的變更。
  5. 最後用 COMMIT 把書的變更提交。

進階範例:多步驟資料處理

現在假設你在做一個訂單管理系統,要同時更新幾個表:orders(訂單)、inventory(庫存)、billing(帳單)。如果某個步驟出錯,你不想讓其他表的進度也跟著沒了。這時 SAVEPOINT 就超好用。

BEGIN;

-- 步驟 1: 建立新訂單
INSERT INTO orders (order_id, customer_id, status) VALUES (1, 123, 'pending');
SAVEPOINT after_order_created;

-- 步驟 2: 更新庫存
UPDATE inventory SET stock = stock - 2 WHERE product_id = 101;
SAVEPOINT after_stock_updated;

-- 步驟 3: 付款
INSERT INTO billing (order_id, amount, status) VALUES (1, 100, 'paid');

-- 哎呀,錯誤:信用卡被拒!
ROLLBACK TO SAVEPOINT after_stock_updated;

-- 我們回到更新庫存後,但訂單還是 "pending" 狀態。
UPDATE orders SET status = 'failed' WHERE order_id = 1;

COMMIT;

注意我們怎麼用 SAVEPOINT 把交易分成幾個邏輯階段,然後回到需要的點,只保留部分變更。

SAVEPOINT 的小技巧

  • 保存點的名字要有意義。上面例子裡的 after_order_createdstep1 好懂多了。
  • 巢狀保存點沒問題:你可以在回滾到某個點後再設新的 SAVEPOINT
  • RELEASE SAVEPOINT 刪掉不需要的保存點可以釋放資源,特別是在大交易裡會提升效能。

真實世界的應用場景

銀行交易處理: 比如你要在多個帳戶間轉帳,如果其中一筆失敗,你可以回到某個階段,不用全部重來。

從檔案匯入資料: 如果你在匯入很大的 CSV 檔,可以一行一行檢查,遇到錯誤只回滾那行,其他成功的都保留。

大量更新資料: 如果你有很複雜的 SQL 腳本要更新成千上萬筆資料,SAVEPOINT 讓你在中間出錯時可以回到前一個階段,不用全部重來。

常見錯誤與陷阱

有時候用 SAVEPOINT 會出現意想不到的狀況,如果你不太懂它怎麼運作的話。比如:

  • 如果你忘了回滾或刪除保存點,可能會讓資源被鎖住直到交易結束。
  • SAVEPOINT 沒辦法取消在設置保存點之前的操作。像是已經 COMMIT 的資料就不能再回滾了。

現在你可以更安心地在交易裡玩保存點了,想設哪裡就設哪裡。接下來還有更多 SQL 實戰,準備好迎接下一波冒險吧!

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