能,savepoint是事务内可回滚的锚点,仅支持回滚到该点之后的所有变更,不能选择性撤销单条语句;必须在显式事务(start transaction)中使用,autocommit=on时无效,innodb引擎支持,ddl会隐式提交致保存点失效。

Savepoint 不是“局部提交”,而是事务内可回滚的锚点;它不能跳过中间语句、不能选择性撤销某一条 UPDATE,只能回滚到该点之后的所有变更。
SAVEPOINT 必须在显式事务中使用
autocommit=ON 时,每条语句自成事务,SAVEPOINT 设了也只活到下一条语句执行前,基本无效。必须先关自动提交或显式开启事务:
-
SET autocommit = 0;或START TRANSACTION; - 之后才能安全执行
SAVEPOINT sp_name; - InnoDB 表才支持——MyISAM 完全无视
SAVEPOINT,查引擎用SHOW CREATE TABLE table_name;
ROLLBACK TO SAVEPOINT 的写法和失效场景
常见错误是漏掉 SAVEPOINT 关键字,写成 ROLLBACK TO sp_name,会直接报错 ERROR 1305 (42000): SAVEPOINT sp_name does not exist。
- 正确写法只有这一种:
ROLLBACK TO SAVEPOINT sp_name; - 隐式提交语句(如
DROP TABLE、ALTER TABLE、CREATE INDEX)会清空所有保存点,且不报错,只悄悄失效 - 触发器内修改无法被外层
ROLLBACK TO SAVEPOINT撤销,除非触发器自己设点并回滚 - 存储过程中若在
DECLARE EXIT HANDLER里执行了ROLLBACK TO SAVEPOINT,但没接COMMIT或后续逻辑,事务会卡住,连接持续占用
命名、覆盖与动态场景中的坑
保存点名不是变量,不能拼接运行时值,比如 SAVEPOINT sp_@i; 会语法报错;也不能用保留字或超长名(上限 64 字符,超长被截断)。
- 同名重复定义:后一次
SAVEPOINT sp1;会静默覆盖前一次,不是报错——循环里固定名sp_step就容易误以为回滚到了“上一轮” - 推荐动态构造:在存储过程里用
CONCAT拼接,例如SET @sp_name = CONCAT('sp_user_', user_id); PREPARE stmt FROM CONCAT('SAVEPOINT ', @sp_name); EXECUTE stmt; - 用完及时
RELEASE SAVEPOINT sp_name;,否则长期大事务可能耗尽会话级保存点资源(虽罕见,但压测中出现过)
它不是嵌套事务,别当“子事务”用
MySQL 根本不支持嵌套事务。START TRANSACTION 嵌套只会隐式提交前一个事务,而不是创建新上下文。唯一能模拟分段控制的方式就是 SAVEPOINT。
- 所谓“回滚到某个步骤”,本质是:事务仍在进行中,只是 undo log 回退到某个偏移位置
-
ROLLBACK TO SAVEPOINT后,必须继续处理(重试、跳过、改逻辑),不能直接丢着不管 - 事务提交或整体回滚时,所有保存点自动清除,无需手动释放——但提前
RELEASE能减少内存驻留
最易被忽略的是 DDL 隐式提交和触发器隔离性:哪怕你把保存点设得再细,一条 ALTER TABLE 就让它全失效;而触发器里干的事,你主流程的保存点根本管不到。











