如何在SQL存储过程中使用SAVEPOINT实现局部事务回滚

秋杰酱_2246

秋杰酱_2246

2026-09-29

966人浏览

原创

savepoint 必须在显式事务中才生效,sql server 默认 autocommit=1,若未由调用方执行 begin transaction,则 save transaction 静默无效,后续 rollback to 会报“savepoint does not exist”;验证需查 @@trancount,值为0即无事务。

如何在sql存储过程中使用savepoint实现局部事务回滚

SAVEPOINT 必须在显式事务中才能生效

存储过程里写 SAVE TRANSACTION sp1 却没回滚?大概率是事务根本没启动。SQL Server 默认 autocommit=1,每条语句自成事务,SAVE TRANSACTION 在这种模式下会静默失败(不报错但后续 ROLLBACK TO sp1 直接提示 “savepoint does not exist”)。

必须由调用方显式开启事务:BEGIN TRANSACTION 或 START TRANSACTION(注意不是在存储过程内部 BEGIN —— 那只是逻辑块,不是事务边界);也不能只靠 SET IMPLICIT_TRANSACTIONS ON,它不可靠且容易被忽略。

  • 验证当前事务状态:SELECT @@TRANCOUNT,值为 0 表示不在事务中
  • DDL 操作(如 CREATE TABLE、ALTER PROCEDURE)会隐式提交,导致所有已设 SAVEPOINT 立即失效
  • 连接池复用时,若上个请求未 COMMIT 或 ROLLBACK,当前请求执行 SAVE TRANSACTION 可能直接报错 “The current transaction cannot be committed and cannot support operations that write to the log file”

命名保存点要带上下文,避免同名覆盖

SAVE TRANSACTION sp1 连续执行两次,第二次会无声覆盖第一次——没有警告,但旧的回滚位置彻底丢失。再执行 ROLLBACK TO sp1 只能回到第二次设点的位置,中间修改全丢。

建议命名体现业务阶段,比如:sp_after_user_insert、sp_before_inventory_deduct。长度别超 32 字符,且大小写敏感(SP1 ≠ sp1)。

  • 变量传参也受限制:@sp_name 必须是 char/varchar 类型,且只取前 32 字符
  • RELEASE SAVEPOINT 在 SQL Server 中不支持(那是 MySQL 语法),SQL Server 无显式释放机制,只能靠事务结束自动清理
  • 事务中途设多个同名点,ROLLBACK TO sp1 总是回到最近一次 SAVE TRANSACTION sp1 的位置

ROLLBACK TO SAVEPOINT 后锁是否释放?看 SQL Server 版本和锁类型

SQL Server 的行为和 MySQL 不同:ROLLBACK TO sp1 会释放该保存点之后获取的**大部分锁**(比如新插入行的 X 锁、UPDATE 涉及的 U 锁),但有例外:

  • 如果之前执行了 SELECT ... WITH (UPDLOCK, HOLDLOCK),这些锁可能被升级为范围锁或保持到事务结束
  • 锁升级后(如从行锁升为页锁),ROLLBACK TO 不会降级或释放
  • 本地变量、表变量内容不受影响,ROLLBACK TO 不会还原它们的值

验证是否真释放:查 sys.dm_tran_locks,过滤 request_session_id = @@SPID,对比回滚前后记录数。

在存储过程中配合 TRY/CATCH 实现局部回滚

不能把 ROLLBACK TO 塞进 CATCH 就完事。必须确保 TRY 块内已设好保存点,且 CATCH 中明确指定目标点名。

典型结构:

BEGIN TRY
    SAVE TRANSACTION sp_after_header;
    INSERT INTO Orders (...) VALUES (...);
    -- 后续可能失败的操作
    EXEC UpdateInventory @order_id;
END TRY
BEGIN CATCH
    IF XACT_STATE()  0
        ROLLBACK TO sp_after_header;
    -- 此处可记录错误,但别再执行可能出错的 DML
    THROW;
END CATCH
  • XACT_STATE() 必须检查:-1 表示不可提交事务,此时 ROLLBACK TO 会失败,只能全量 ROLLBACK
  • 不要在 CATCH 里再调用含 DDL 或跨库操作的过程,容易引发嵌套异常
  • THROW 要放在最后,否则错误信息被吞掉,上游无法感知失败

最易被忽略的是:保存点只对当前连接、当前事务有效。存储过程中调用的函数或触发器,其内部 SAVE TRANSACTION 和外层完全隔离,退出即销毁,不能跨作用域引用。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

3843

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

831

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1009

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

5661

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

2623

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

5640

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

7421

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1010

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

892

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.3万人学习