savepoint 仅是事务内可回滚标记点,非局部事务;须在 autocommit=0 的显式事务中使用,否则静默失效;rollback to savepoint 回退数据但不释放行锁;同名保存点会覆盖,ddl 或 myisam 等场景使其失效。

MySQL 的 SAVEPOINT 不是“局部事务”,只是当前事务内一个可回滚的标记点;它不复制数据、不隔离锁、也不能跨语句选择性撤销——用错就以为控制住了,其实只回退了 undo log 位置。
SAVEPOINT 必须在显式事务中使用,autocommit=1 下完全无效
MySQL 默认 autocommit=1,此时每条语句自成事务,SAVEPOINT 会静默失败(比如返回 Query OK,但后续 ROLLBACK TO SAVEPOINT sp1 直接报 ERROR 1305 (42000): SAVEPOINT sp1 does not exist)。
- 先确认会话模式:
SELECT @@autocommit;,必须为0 - 仅
SET autocommit = 0不够,必须显式执行BEGIN或START TRANSACTION - 连接池复用时,若上个请求未
COMMIT或ROLLBACK,当前请求一执行SAVEPOINT就可能报Transaction is not active
ROLLBACK TO SAVEPOINT 后数据回退,但行锁不释放
ROLLBACK TO SAVEPOINT sp1 会撤销该点之后所有 DML(如 INSERT、UPDATE、DELETE),但 InnoDB **不会释放这些操作持有的行锁**——尤其是新插入行的锁,要等到整个事务 COMMIT 或全量 ROLLBACK 才真正释放。
- 你
INSERT一行又ROLLBACK TO SAVEPOINT,另一事务想UPDATE同一行,仍会被阻塞 - 若保存点后执行了
SELECT ... FOR UPDATE,锁持续持有,直到事务结束 - 验证是否真回退?别信返回信息,直接
SELECT查表;查锁状态可用information_schema.INNODB_TRX和INNODB_LOCK_WAITS
同名 SAVEPOINT 静默覆盖,命名和 RELEASE 得自己管
执行两次 SAVEPOINT sp1,第二次会覆盖第一次——不报错、不警告,但旧的 sp1 对应的 undo log 位置和 binlog offset 已丢失,再 ROLLBACK TO SAVEPOINT sp1 只能回到第二次设点的位置。
- 命名建议带业务上下文,如
sp_after_header_insert、sp_before_batch_update,避免纯数字或通用名 -
RELEASE SAVEPOINT sp1是唯一显式清理方式;不释放也不会报错,但容易误判逻辑断点 - 事务结束(
COMMIT或全量ROLLBACK)时,所有保存点自动清除,无需手动RELEASE,但中间过程主动释放更清晰
哪些操作会让 SAVEPOINT 失效或行为异常
SAVEPOINT 不是万能锚点,遇到隐式提交或引擎限制,它会当场“消失”。
-
DROP TABLE、ALTER TABLE等 DDL 语句会触发隐式COMMIT,前面所有SAVEPOINT立即失效 - MyISAM 引擎不支持事务,
SAVEPOINT会静默忽略(无报错但无效) - 触发器内发生的修改,无法被外层
ROLLBACK TO SAVEPOINT撤销(除非触发器自己设点) - 在存储过程中调用
ROLLBACK(非TO SAVEPOINT),会清空整个事务及所有保存点 - 拼错保存点名、大小写不一致(
sp1≠SP1)都会导致ERROR 1305
真正难处理的不是语法,而是锁生命周期与保存点边界的错位——你以为回退了,其实锁还卡着别人;你以为设了点就能兜底,结果一条 ALTER 就让它彻底失效。这些细节不验证、不监控,上线后只会变成深夜排查的谜题。











