SQL 保存点
学习SAVEPOINT · 难度:高级 · +15XP
SQL 保存点(SAVEPOINT)
在事务处理中,有时你只想回滚部分操作而不是整个事务。比如在一个包含 10 个步骤的事务中,第 7 步出错了,你只想撤销第 5-7 步,保留前 4 步的成果。SQL 的 SAVEPOINT(保存点)机制就是为这种场景设计的,它允许你在事务中设置标记点,之后可以精确回滚到指定标记而非事务开头。
SAVEPOINT 基本语法
-- 创建保存点
SAVEPOINT 保存点名称;
-- 回滚到指定保存点
ROLLBACK TO 保存点名称;
-- 释放保存点(某些数据库支持)
RELEASE SAVEPOINT 保存点名称;
完整示例
以下示例模拟一个银行转账场景,展示保存点的实际用法:
-- 开始事务
BEGIN;
-- 步骤1:从账户A扣款100元
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 设置保存点A_deducted
SAVEPOINT A_deducted;
-- 步骤2:向账户B加款100元
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- 设置保存点B_added
SAVEPOINT B_added;
-- 步骤3:记录转账日志(假设这里出错了)
INSERT INTO transfer_log(account_from, account_to, amount)
VALUES (1, 2, 100);
-- 发现日志表不存在,回滚到B_added
ROLLBACK TO B_added;
-- 重新记录日志(或跳过)
INSERT INTO transfer_log(account_from, account_to, amount)
VALUES (1, 2, 100);
-- 全部完成,提交
COMMIT;
SAVEPOINT 的重要规则
| 规则 | 说明 |
|---|---|
| 保存点在事务内 | SAVEPOINT 只能在事务(BEGIN/START TRANSACTION)内部使用 |
| 回滚后保存点不删除 | ROLLBACK TO 某保存点后,该保存点仍然存在,可以再次回滚到它 |
| 回滚删除后续点 | 回滚到前面的保存点时,之后创建的保存点会被删除 |
| COMMIT 清除所有 | 提交事务后,所有保存点自动释放 |
| 同名覆盖 | 创建同名保存点会覆盖之前的同名保存点 |
适用场景
- 批量数据处理:处理多条记录时,每条记录设置保存点,出错只回滚当前记录
- 复杂业务流程:多步骤操作中,每步完成后设置保存点
- 测试与调试:在 SQL 脚本中分段设置保存点,方便分段回滚测试
- 嵌套事务模拟:在 MySQL(不原生支持嵌套事务)中模拟嵌套事务效果
数据库兼容性
SAVEPOINT 是 SQL 标准,主流数据库都支持:MySQL、PostgreSQL、Oracle、SQLite、SQL Server。但语法细节可能略有差异。
实战任务
- 在一个事务中插入 3 条学生记录,每条插入后设置保存点
- 回滚到第 2 个保存点,观察最终提交后表中保留了几条数据
- 尝试在事务外使用 SAVEPOINT,观察报错信息