想像一下你在寫一本書。但很衰的是:事情不總是照計劃走。有時你寫了一整章,結果重看時發現第 5 段超爛。你會怎麼辦?你不會直接把整章丟掉吧?通常你只會改掉那些你覺得怪怪的地方。
SAVEPOINT 在 PostgreSQL 裡的用法就很像這樣。它讓你可以:
- 在交易裡設置保存點——就像在書裡放書籤一樣。
- 回到這些保存點,只取消從那時候開始的部分操作,不用把整個交易都回滾。
- 繼續處理剩下的資料,不用重來一次。
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;
這個例子發生了什麼?
- 我們用
BEGIN開始了一個交易。 - 預留書之後設了一個保存點
book_reserved。這是我們的第一個「checkpoint」。 - 試著預留馬克杯,但出錯了(比如庫存不足)。
- 我們回到
book_reserved,只取消跟馬克杯有關的變更。 - 最後用
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_created比step1好懂多了。 - 巢狀保存點沒問題:你可以在回滾到某個點後再設新的
SAVEPOINT。 - 用
RELEASE SAVEPOINT刪掉不需要的保存點可以釋放資源,特別是在大交易裡會提升效能。
真實世界的應用場景
銀行交易處理: 比如你要在多個帳戶間轉帳,如果其中一筆失敗,你可以回到某個階段,不用全部重來。
從檔案匯入資料: 如果你在匯入很大的 CSV 檔,可以一行一行檢查,遇到錯誤只回滾那行,其他成功的都保留。
大量更新資料: 如果你有很複雜的 SQL 腳本要更新成千上萬筆資料,SAVEPOINT 讓你在中間出錯時可以回到前一個階段,不用全部重來。
常見錯誤與陷阱
有時候用 SAVEPOINT 會出現意想不到的狀況,如果你不太懂它怎麼運作的話。比如:
- 如果你忘了回滾或刪除保存點,可能會讓資源被鎖住直到交易結束。
SAVEPOINT沒辦法取消在設置保存點之前的操作。像是已經COMMIT的資料就不能再回滾了。
現在你可以更安心地在交易裡玩保存點了,想設哪裡就設哪裡。接下來還有更多 SQL 實戰,準備好迎接下一波冒險吧!
GO TO FULL VERSION