在PostgreSQL里,没有真正意义上的嵌套事务。只有一个外部事务和里面的“保存点层”。
在PostgreSQL里,“嵌套事务”这个词通常指的是用保存点(savepoints),也就是用SAVEPOINT、ROLLBACK TO SAVEPOINT、RELEASE SAVEPOINT这些命令。这些不是独立的事务,而是外部事务里的特殊检查点,你可以回滚到这些点,而不用把整个事务都撤销。
生活中的例子:你在编辑器里写一大段文字,时不时按一下ctrl+s。如果你写错了,可以回到之前保存的某个版本,不会丢掉所有进度。
保存点管理的命令
为了管理嵌套事务,PostgreSQL提供了三个主要命令:
SAVEPOINT
这个命令用来创建“保存点”,你可以在需要的时候回滚到这里。保存点就像事务里的检查站。
SAVEPOINT mypoint;
ROLLBACK TO SAVEPOINT
回滚部分更改,就是回到指定保存点后,后面的更改都撤销了,但更早的更改还在同一个外部事务里保留。
ROLLBACK TO SAVEPOINT mypoint;
RELEASE SAVEPOINT
删除保存点。删了之后就不能再回滚到这个点了。
RELEASE SAVEPOINT mypoint;
例子:往多张表插数据还能回滚
假设你在做一个订单管理系统,需要同时往orders和order_items两张表插数据。如果往一张表插入出错,不应该把另一张表的数据也撤销。
BEGIN; -- 事务开始
-- 创建保存点
SAVEPOINT before_order;
-- 往orders表插入订单
INSERT INTO orders (order_id, customer_id, date)
VALUES (1, 101, CURRENT_DATE);
-- 如果这里出错 — 回滚
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;
如果在往order_items插入数据时出错,可以回滚到before_order_items,而orders表里的更改还会保留。
实用建议和常见坑
现在你已经明白SAVEPOINT和ROLLBACK TO SAVEPOINT怎么用了,下面这些建议可以帮你少踩坑:
- 保存点的名字。给
SAVEPOINT起个有意义又独特的名字,比如before_insert、step1啥的,这样调试的时候更容易看懂。 - 别忘了释放
SAVEPOINT。如果你不打算再回到某个保存点了,用RELEASE SAVEPOINT把它删掉,别让事务里堆太多没用的保存点。 - 嵌套事务 ≠ 独立事务。记住,执行
COMMIT的时候,所有保存点都会消失。外部COMMIT一旦执行,就没法再回滚了。 - 数据锁。即使你回滚到某个保存点,事务里加的锁还在。多用户环境下要注意这个问题。
用SAVEPOINT和ROLLBACK TO SAVEPOINT做嵌套事务,能让开发者灵活处理各种复杂情况。你可以把事务拆成多个阶段,优雅地处理错误,避免没必要的数据回滚。记住,每次看到“回滚”这个词,不一定要慌,有时候回滚才是最好的前进方式。
GO TO FULL VERSION