Sql server 在存储过程中使用SAVE TRANSACTION SavePointName
我不清楚是否需要为我使用的每个SP使用不同的保存点名称Sql server 在存储过程中使用SAVE TRANSACTION SavePointName,sql-server,tsql,stored-procedures,transactions,savepoints,Sql Server,Tsql,Stored Procedures,Transactions,Savepoints,我不清楚是否需要为我使用的每个SP使用不同的保存点名称保存事务 即使较高级别的事务使用相同的保存点名称,我是否可以始终使用例如保存事务过程保存点和回滚事务过程保存点 我的SP签名如下: ALTER PROCEDURE [dbo].[usp_MyTask]() AS BEGIN DECLARE @iReturn int = 0 DECLARE @tranCount int = @@TRANCOUNT; IF @tranCount > 0 SAVE T
保存事务
即使较高级别的事务使用相同的保存点名称,我是否可以始终使用例如保存事务过程保存点
和回滚事务过程保存点
我的SP签名如下:
ALTER PROCEDURE [dbo].[usp_MyTask]()
AS
BEGIN
DECLARE @iReturn int = 0
DECLARE @tranCount int = @@TRANCOUNT;
IF @tranCount > 0
SAVE TRANSACTION ProcSavePoint;
ELSE
BEGIN TRAN
...
IF <some condition>
BEGIN
@iReturn = 1
GOTO Undo
END
...
IF @tranCount = 0
COMMIT TRAN
RETURN
Undo:
IF @tranCount = 0 -- transaction started in procedure. Roll back complete transaction.
ROLLBACK TRAN;
ELSE
IF XACT_STATE() <> -1 ROLLBACK TRANSACTION ProcSavePoint;
RETURN @iReturn
END
ALTER过程[dbo]。[usp\u MyTask]()
作为
开始
声明@iReturn int=0
声明@tranCount int=@@tranCount;
如果@tranCount>0
保存事务保存点;
其他的
开始训练
...
如果
开始
@i返回=1
去撤销
结束
...
如果@tranCount=0
提交传输
返回
撤消:
如果@tranCount=0——事务已在过程中启动。回滚完整事务。
回滚传输;
其他的
如果XACT_STATE()-1回滚事务保存点;
返回@iReturn
结束
希望我的问题是清楚的。从技术上讲,是的,您可以重复使用相同的存储点名称,并且它们会堆积起来,就像对
BEGIN-TRAN
的多次调用一样,其中对COMMIT
的每次调用都会使计数器递减。也就是说,如果您发出savetransactionprocsavepoint
5次,然后调用rollbacktransactionprocsavepoint
2次,在第三次调用SAVE TRAN
和第四次调用它之前,您仍将保持事物所处的状态
但是,此代码在几个级别上存在问题:
转到Undo
的条件,如果您有一种情况,即调用嵌套过程5个级别,然后级别5成功完成,然后级别4成功完成,但级别3决定转到“Undo”,它将执行回滚事务ProcSavePoint代码>只会回滚第五级。这会让你处于一种糟糕的状态,因为你的目的是要回到3级开始时的状态
使用唯一的保存点名称可以解决此问题
TRY
/CATCH
结构。你真的应该。如果您有基于非SQL Server错误的特定条件决定取消操作的逻辑,您仍然可以通过调用RAISERROR()
立即转到CATCH
块来强制取消操作。或者,如果您不想将其作为错误处理,除了使用TRY
/CATCH
之外,您还可以使用转到undo
方法XACT\u STATE()
可以在TRY
/CATCH
构造之外报告-1
COMMIT
我最常使用的模板显示在我对DBA.StackExchange上此问题的回答中:。该模板只是在开始时检查活动事务(类似于您的方法),但如果存在活动事务,则不会执行任何操作。因此,永远不会调用额外的BEGIN-TRAN
或甚至SAVE-TRAN
,只有后面的外部(即使是app-code)将执行COMMIT
或ROLLBACK
请指出这一点,因为您的代码与我在链接答案中发布的代码之间似乎存在功能上的差异,但事实并非如此:没有特别需要捕获@@TRANCOUNT
的实际值,因为唯一的选项是0
或>0
,除非进入模板时@@TRANCOUNT
已经大于1,否则它将得到的最大值无论如何都是1(如果触发器和/或插入到…EXEC
增量中,即使有活动事务,也可能是2)。在这两种情况下,我对@InNestedTransaction
使用位
变量在功能上/逻辑上等同于将@@tracount
存储在INT
变量中,因为SAVE TRAN
不会递增@@tracount
您是否在询问是否可以在另一个会话中使用相同的保存点名称?是否存在外层可能会继续并最终提交的情况,即使子进程调用中发生错误?对调用者进程从子进程返回一个返回值,并在需要时回滚。我假设对于未处理的sql server异常,整个转换都会回滚,不是吗?在任何情况下,我总是向我的客户机应用程序报告返回代码。请让我再评估一下你的答案…@zig听起来你确实有一个很好的理由去做TRY/CATCH和你的“undo”标签,我猜这将出现在
TRY
块的末尾。如果没有TRY/CATCH构造,管理起来就有点困难,因为有些错误只中止语句,有些则中止批处理。如果使用将XACT\u ABORT设置为ON
,则所有错误将中止整个批处理,并在CATCH
块内从XACT\u STATE()
返回-1
;但是,我不喜欢在上使用XACT\u ABORT。谢谢@srutzky,你给了我很多好信息。我可能需要重新考虑我的模板,因为我总是返回一个表示托管错误的值(通常是验证错误)。永远不要使用TRY/CATCH思维XACT\u ABORT ON
始终处于启用状态:/@zig我对您上面的代码有一个问题。此语句是否“如果'@tranCount'=0提交传输返回”正确。我的意思是,如果Trancount为零,那么COMMIT TRAN将给出错误。如果我在这里错了或不见了,请纠正我something@sam,@tranCount=0
(局部变量最初设置为。@@TRAN