十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

TiDB 事务只回滚一半:SAVEPOINT 的 3 个命令

TiDB 事务只回滚一半:SAVEPOINT 的 3 个命令 TiDB 事务只回滚一半SAVEPOINT 的 3 个命令【免费下载链接】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长事务写错中间几步TiDB 的 SAVEPOINT 让你只对这部分做部分回滚撤销保存点之后的写入事务继续可用还能接着写入、正常提交。什么场景需要只回滚一半长事务往往一捆语句绑在一起执行。跑到一半发现最后几条 INSERT 有问题直接ROLLBACK会把整个事务的修改全丢掉代价很大。这就是保存点想解决的痛点它在事务中间打一个检查点需要时只撤销检查点之后的写入。检查点之前的修改保留事务本身不结束后续语句照常执行。用 ORM 的同学应该有感觉。gorm 这类框架里手写的部分回滚套路本质是在用多条语句模拟同一件事。数据库原生支持保存点后这套轮子可以不重造。三条命令各管一件事三条命令对应 TiDB 保存点用法的三个职责各记一个注意点。SAVEPOINT在当前事务里记录一个具名检查点。注意保存点名区分大小写s1和S1是两个名字。同名重复执行时旧的同名保存点先被删除再记录新的检查点不会报错。ROLLBACK TO SAVEPOINT把事务回退到指定检查点。其后的数据修改全部撤销但事务不结束可以继续写入。ROLLBACK TO s1是它的等价简写两者效果一致。RELEASE SAVEPOINT删除该保存点及其之后的所有保存点。注意它既不提交也不回滚事务只是清理检查点列表。SAVEPOINT s1; INSERT INTO t VALUES (2, 2); ROLLBACK TO s1; RELEASE SAVEPOINT s1;四连读先立检查点再插一行撤销这一行最后清掉检查点。跟着跑一遍悲观事务里的保存点实战以下流程用悲观事务演示乐观事务同样适用。表结构带一个唯一索引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);这一步做完事务里有两行检查点立在第一行之后。ROLLBACK TO s1; INSERT INTO t VALUES (2, 2); SELECT * FROM t;回退只撤销 (2,2) 的插入。事务仍可用所以同一行可以重新插入事务内 SELECT 能看到 (1,1) 和 (2,2) 两行。ROLLBACK TO s1; SELECT * FROM t; COMMIT; SELECT * FROM t;保存点可以反复使用。再回退一次事务内只剩 (1,1)提交后查询结果一致落盘的只有保存点前写入的那一行。怎么确认某个保存点还在没有语句能直接查保存点状态只能再执行一次ROLLBACK TO看是否报SAVEPOINT ... does not exist来间接判断。再看保存点前做过 DELETE 的情况DELETE FROM t WHERE id 1; SAVEPOINT s1; INSERT INTO t VALUES (1, 2); ROLLBACK TO s1; SELECT * FROM t;新插入的 (1,2) 被撤销但保存点前的删除保留查询结果为空提交后依然为空。记住一句话只回之后不动之前。临时表也支持保存点。BEGIN之后对临时表依次建 sp0、sp1ROLLBACK TO sp1后事务内查询只保留到 sp1 为止的行。ON COMMIT DELETE ROWS的全局临时表同理逐层回退逐层生效COMMIT后行被清空。保存点的栈逻辑与生效前提保存点列表像栈新保存点压栈删除时一次删掉一段。两条维护规则决定后续语句还能不能跑ROLLBACK TO SAVEPOINT name删除目标之后的全部保存点目标本身保留。RELEASE SAVEPOINT name删除目标及其后的全部保存点事务不提交、不回滚。SAVEPOINT s1; SAVEPOINT s2; SAVEPOINT s3; ROLLBACK TO s2; ROLLBACK TO s3; -- s3 已被删此行报错这段代码演示栈规则回退到 s2 时 s3 自动消失再碰 s3 就会报错。再看三个生效前提缺一个保存点就不工作只在显式事务内生效。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。和 MySQL 对比容易踩的两个点锁什么时候放。MySQL 在ROLLBACK TO SAVEPOINT时就释放保存点之后持有的锁。TiDB 悲观事务不立即放而是等事务提交或整体回滚时统一释放。实际影响回退之后另一个会话对相应行执行FOR UPDATE仍可能等到本事务结束。遇到这种情况别误判成没回滚干净。自增值回不回。不回。回退保存点不回收已分配的 AUTO_INCREMENT / SEQUENCE 值这是与 MySQL 一致的预期行为。实际影响提交后的主键存在空洞拿序列值做对账或审计时别假设它连续。动手前先记住的报错速查现象 / 报错触发条件处理方式SAVEPOINT is not supported when binlog is enabled实例开启了 binlog保存点不可用改用整事务回滚或关闭 binlogsavepoint is not supported in pessimistic transactions when in-place constraint check is disabled悲观事务且tidb_constraint_check_in_place_pessimistic为 OFF打开该会话变量再使用保存点不报错但保存点没生效未在显式事务内autocommit把语句放进BEGIN ... COMMIT里执行[executor:1305]SAVEPOINT s1 does not exist回退或释放的保存点不存在名称大小写不符也算检查拼写与大小写确认该保存点未被后续回退清掉提交后 AUTO_INCREMENT / SEQUENCE 出现空洞执行过回退保存点预期行为值不回收不要依赖主键严格连续回退后其他会话FOR UPDATE仍在等待TiDB 悲观事务的锁释放时机锁在提交或整体回滚时统一释放等待属正常现象【免费下载链接】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),仅供参考
返回列表