
TiDB 长事务只回滚一半SAVEPOINT 部分回滚实操速查【免费下载链接】tidbTiDB is built for agentic workloads that grow unpredictably, with ACID guarantees and native support for transactions, analytics, and vector search. No data silos. No noisy neighbors. No infrastructure ceiling.项目地址: https://gitcode.com/GitHub_Trending/ti/tidb一个长事务执行到一半后面几步写入出了问题直接ROLLBACK会把之前所有修改一起丢掉。TiDB 支持标准的保存点语法用SAVEPOINT在事务内打一个检查点再执行ROLLBACK TO SAVEPOINT只撤销该检查点之后的写入事务本身仍然可以继续写入并提交。乐观、悲观两种事务模式均支持这正是 gorm 等 ORM 框架常用的部分回滚诉求。保存点使用前提三个必须先确认的条件 用之前先核对这三条否则语句会报错或被静默忽略保存点只在显式事务内生效。不在事务中且 autocommit 开启时执行SAVEPOINT不报错但属于空操作之后执行ROLLBACK TO会报保存点不存在。binlog 开启的实例不可用SAVEPOINT直接报SAVEPOINT is not supported when binlog is enabled。TiDB 4.0 之后官方已不建议启用 binlog多数部署不受影响。悲观事务要求 in-place constraint check 开启。会话变量tidb_constraint_check_in_place_pessimistic为关闭状态时悲观事务中执行SAVEPOINT会报savepoint is not supported in pessimistic transactions when in-place constraint check is disabled。相关判断逻辑见执行入口行为定义见设计文档。如何创建保存点三条语句与命名规则SAVEPOINT s1; -- 记录当前事务的检查点 ROLLBACK TO SAVEPOINT s1; -- 回退到 s1可简写为 ROLLBACK TO s1 RELEASE SAVEPOINT s1; -- 删除 s1不提交也不回滚两个容易踩坑的命名细节保存点名区分大小写。创建s1之后ROLLBACK TO S1会被当作一个不存在的保存点。同名重复执行SAVEPOINT不报错旧的同名保存点先被删除再记录新的检查点。最小可运行示例悲观事务中的部分回滚 ✅以下场景与集成测试中的TestRollbackToSavepoint一致测试脚本DROP TABLE IF EXISTS t; CREATE TABLE t(id int, a int, UNIQUE INDEX idx(id)); BEGIN PESSIMISTIC; INSERT INTO t VALUES (1, 1); SAVEPOINT s1; INSERT INTO t VALUES (2, 2);回退到s1只撤销(2,2)事务并不结束可以立即继续写ROLLBACK TO s1; INSERT INTO t VALUES (2, 2); SELECT * FROM t; -- 返回 (1,1) 和 (2,2) 两行同一保存点可以反复回退提交后只有检查点之前的修改落盘ROLLBACK TO s1; SELECT * FROM t; -- 只剩 (1,1) COMMIT; SELECT * FROM t; -- 仍只有 (1,1)检查点之前的删除不会被撤销保存点只保护之后的修改之前的操作原样保留DELETE FROM t WHERE id 1; SAVEPOINT s1; INSERT INTO t VALUES (1, 2); ROLLBACK TO s1;此时表为空(1,2)被撤销但s1之前的删除仍然生效COMMIT之后依旧为空。临时表同样适用BEGIN之后对临时表创建sp0/sp1再ROLLBACK TO sp1事务内查询只保留到sp1为止的行对ON COMMIT DELETE ROWS的全局临时表sp2→sp1逐层回退依次生效COMMIT后行被清空。保存点列表如何维护回退会删掉谁 ⚠️保存点按栈的方式保存在事务上下文中两条维护规则直接决定后续语句能不能执行ROLLBACK TO SAVEPOINT name删除目标之后的所有保存点只保留目标本身。依次创建 s1、s2、s3 后执行ROLLBACK TO s2s3 即被删除再执行ROLLBACK TO s3会报错。RELEASE SAVEPOINT name删除该保存点和它之后的全部保存点但不提交、不回滚事务。保存点不存在时ROLLBACK TO与RELEASE SAVEPOINT返回统一错误见 txn_test.go[executor:1305]SAVEPOINT s1 does not exist测试同时验证了大小写敏感创建s1后ROLLBACK TO S1报同样的错。TiDB 与 MySQL 的两处行为差异 设计文档 明确列出了兼容性差异写跨库逻辑时务必注意锁的释放时机不同。MySQL 在ROLLBACK TO SAVEPOINT时释放保存点之后持有的锁TiDB 悲观事务不会立即释放而是等事务提交或整体回滚时统一释放。因此回退之后其他会话对相应行的FOR UPDATE请求仍可能阻塞到事务结束。AUTO_INCREMENT 与 SEQUENCE 不回滚。回退保存点不会回收已分配的自增值提交后这些值存在空洞。这一点与 MySQL 行为一致。如何验证保存点是否生效事务内直接SELECT目标表对比回退前后的行数与内容确认保存点之后的写入是否被撤销。提交后再次SELECT确认落盘数据只包含最后一次回滚点之前的修改。保存点状态没有 SQL 可以直接查询只能通过再次执行ROLLBACK TO/RELEASE SAVEPOINT是否报SAVEPOINT ... does not exist来间接判断。保存点限制与常见错误速查binlog 开启SAVEPOINT is not supported when binlog is enabled悲观事务且 in-place constraint check 关闭SAVEPOINT执行即报错不在事务内SAVEPOINT静默忽略后续ROLLBACK TO报[executor:1305]SAVEPOINT ... does not existAUTO_INCREMENT / SEQUENCE 值不回退重用提交后出现空洞悲观锁不随回退释放统一在 commit / rollback 时释放保存点是 TiDB 里做部分回滚的正统手段记住事务内才生效、名称区分大小写、ROLLBACK TO会截断栈顶这三点就能替代各种 ORM 的部分回滚套路。处理长事务时建议按逻辑阶段各打一个检查点出问题时只回退最近一段而不是推倒整个事务重来。【免费下载链接】tidbTiDB is built for agentic workloads that grow unpredictably, with ACID guarantees and native support for transactions, analytics, and vector search. No data silos. No noisy neighbors. No infrastructure ceiling.项目地址: https://gitcode.com/GitHub_Trending/ti/tidb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考