savepoint 是事务内设置的标记点,支持回滚到该点而非整个事务;rollback 则清空全部事务操作。savepoint 不提交数据、不释放锁、可多次定义且名字唯一,而 commit 后所有 savepoint 失效。

什么是 Savepoint,它和 ROLLBACK 有什么区别?
SAVEPOINT 是 MySQL 中用于在事务内设置一个“标记点”的机制,不是独立事务,也不提交任何数据。它让 ROLLBACK TO SAVEPOINT 能把事务回滚到该点,而不是整个事务——这点和直接用 ROLLBACK 有本质区别:后者会清空整个事务上下文,前者只撤销之后的操作。
-
SAVEPOINT不会释放锁(行锁仍保持),也不会影响已加的锁范围 - 同一个事务中可设多个
SAVEPOINT,名字必须唯一,重复定义会覆盖旧的 -
RELEASE SAVEPOINT只是删掉标记,不影响数据或锁,但后续不能再ROLLBACK TO它
怎么正确使用 SAVEPOINT 实现部分回滚?
核心流程是:开启事务 → 执行操作 → 设 SAVEPOINT → 继续操作 → 出错时 ROLLBACK TO SAVEPOINT → 最后 COMMIT 或 ROLLBACK 整体事务。
START TRANSACTION; INSERT INTO orders (user_id, amount) VALUES (101, 299.9); SAVEPOINT after_order; UPDATE accounts SET balance = balance - 299.9 WHERE user_id = 101; -- 假设这里出错(比如余额不足),我们不想丢掉订单插入 ROLLBACK TO SAVEPOINT after_order; -- 此时 orders 表里那条记录还在,accounts 没变 COMMIT;
-
SAVEPOINT名字建议带语义(如after_insert_user),避免用sp1这类无意义名 -
ROLLBACK TO SAVEPOINT后,该SAVEPOINT依然存在,可再次回滚到它(除非显式RELEASE) - 如果执行了
COMMIT,所有SAVEPOINT自动失效,再用会报错ERROR 1305 (42000): SAVEPOINT does not exist
常见踩坑场景和兼容性注意
MySQL 5.6+ 支持 SAVEPOINT,但不同存储引擎行为不一致:
-
InnoDB完全支持,包括锁保留、MVCC 快照一致性 -
MyISAM不支持事务,设SAVEPOINT不报错但无效,ROLLBACK TO会静默失败 - 在存储过程里用
DECLARE EXIT HANDLER捕获异常后,要小心ROLLBACK TO是否在 handler 作用域内生效
容易忽略的细节:
-
SAVEPOINT不能跨连接使用,每个客户端连接的事务上下文隔离 - 如果事务中执行了 DDL(如
ALTER TABLE),MySQL 会隐式提交当前事务,所有SAVEPOINT立即失效 -
INSERT ... ON DUPLICATE KEY UPDATE触发唯一键冲突时,不会自动触发SAVEPOINT回滚,得靠业务逻辑判断后手动回退
什么时候不该依赖 SAVEPOINT?
它不是万能的“局部事务”替代品:
- 涉及多表强一致性校验(如库存扣减 + 订单生成 + 物流单创建),靠
SAVEPOINT回滚可能留下中间态脏数据,应改用应用层补偿或 Saga 模式 - 高并发写同一行时,
SAVEPOINT不解决死锁问题;ROLLBACK TO后重试仍可能再次死锁 - 日志类、审计类写入(如
INSERT INTO logs)若放在SAVEPOINT之后,回滚后日志也消失,可能丢失关键操作痕迹
真正需要部分回滚的场景其实不多,多数时候是业务逻辑没拆清边界。先想清楚:这一步“可逆”是否真的安全,比急着写 SAVEPOINT 更重要。











