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, '待处理');
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, '已支付');

-- 哎呀,出错了:信用卡被拒!
ROLLBACK TO SAVEPOINT after_stock_updated;

-- 我们回到更新库存之后,但订单还是“待处理”状态。
UPDATE orders SET status = '失败' WHERE order_id = 1;

COMMIT;

注意我们怎么用 SAVEPOINT 把事务分成逻辑步骤,回到需要的点,只保留一部分更改。

SAVEPOINT 的小贴士

  • 保存点名字要有意义。上面例子里的 after_order_createdstep1 这种强多了。
  • 嵌套保存点没问题:你可以在回滚到某个点后再创建新的 SAVEPOINT
  • RELEASE SAVEPOINT 删除不需要的保存点,能释放资源,尤其是大事务里能提升性能。

实际应用场景

银行业务处理: 比如多账户之间转账时,如果某一步失败了,你可以回滚到某个阶段。

从文件导入数据: 导入大 CSV 文件时,可以一行一行检查,出错只回滚那一行,成功的都保留。

批量更新记录: 如果你有个复杂 SQL 脚本要更新成千上万行,SAVEPOINT 让你在中途出错时回到上一步。

常见错误和坑

有时候用 SAVEPOINT 会遇到意外情况,主要是你没搞懂它怎么工作。比如:

  • 如果你忘了回滚或删除保存点,可能会导致资源一直被锁,直到事务结束。
  • SAVEPOINT 不能撤销在保存点之前发生的操作。比如已经 COMMIT 的数据就没法再回滚了。

现在你可以放心大胆地在事务里玩 SAVEPOINT,想设哪就设哪。后面还有更多 SQL 实战,准备好迎接新一轮的挑战吧!

2
任务
SQL SELF, 第 39 级, 课程 2
已锁定
用 `SAVEPOINT` 简单撤销更改
用 `SAVEPOINT` 简单撤销更改
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION