sql-server – 如何从一个存储过程启动3个存储过程时回滚
|
我有一个存储过程,只在其中执行3个存储过程.如果主SP成功,我只使用1个参数来存储. 如果第一个存储过程在主存储过程中正常工作,但第二个存储过程失败,那么它会自动回滚主SP中的所有SP还是我必须做一些命令? 这是我的程序: CREATE PROCEDURE [dbo].[spSavesomename]
-- Add the parameters for the stored procedure here
@successful bit = null output
AS
BEGIN
begin transaction createSavebillinginvoice
begin Try
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN
EXEC [dbo].[spNewBilling1]
END
BEGIN
EXEC [dbo].[spNewBilling2]
END
BEGIN
EXEC [dbo].[spNewBilling3]
END
set @successful = 1
end Try
begin Catch
rollback transaction createSavesomename
insert into dbo.tblErrorMessage(spName,errorMessage,systemDate)
values ('spSavesomename',ERROR_MESSAGE(),getdate())
return
end Catch
commit transaction createSavesomename
return
END
GO
解决方法仅给出问题中显示的代码,并假设三个子过程中没有一个具有任何显式事务处理,则是,将捕获三个子过程中的任何一个中的错误并且CATCH块中的ROLLBACK将滚动回来所有的工作.但是这里有一些关于事务的注意事项(至少在SQL Server中): >无论您多少次拨打BEGIN TRAN,都只有一次真正的交易(第一次) >您可以命名一个事务(就像您在此处所做的那样)并且该名称将出现在日志中,但命名仅对第一个/最外部事务具有意义(因为同样,第一个事务是事务). >保存点允许在事务中创建可撤消的工作子集. >通过SAVE TRAN {save_point_name}命令创建/标记保存点 >您无法提交特定的命名事务.事务“名称”(如果与COMMIT一起提供)将被忽略,仅出于可读性而存在. >第一个事务,假设它被命名为: BEGIN TRAN A -- @@TRANCOUNT is now 1 -- DML Query 1 SAVE TRAN A -- DML Query 2 SAVE TRAN A -- DML Query 3 BEGIN TRAN B -- @@TRANCOUNT is now 2 SAVE TRAN B -- DML Query 4 现在,如果您发布(以下每个方案彼此独立): > ROLLBACK TRAN B一次:它将撤消“DML Query 4”. @@ TRANCOUNT仍然是2. >交易名称和保存点名称: >最多可包含32个字符 >存储过程本身不是隐式事务.如果没有启动显式事务,则每个查询都是隐式事务.这就是为什么不需要围绕单个查询的显式事务,除非可能有编程原因来执行ROLLBACK,否则查询中的任何错误都是该查询的自动回滚. >在proc中启动BEGIN TRAN而不提交它,期望在调用/父进程中提交. 如果退出存储过程的事务计数高于或低于它的凝视时间,则会出现类似于以下内容的错误:
>表变量与常规变量一样,不受事务约束. 关于在proc中进行事务处理,可以独立调用(因此需要事务处理)或从其他proc调用(因此不需要事务处理):这可以通过几种不同的方式完成. 我多年来一直处理它的方式似乎运行良好的是在最外层只有BEGIN / COMMIT / ROLLBACK.子proc调用只是跳过事务命令.我在下面概述了我在每个proc中放入的内容(好吧,每个需要事务处理的内容). >在每个proc的顶部,DECLARE @InBestedTransaction BIT; IF (@@TRANCOUNT = 0) BEGIN SET @InNestedTransaction = 0; BEGIN TRAN; -- only start a transaction if not already in one END; ELSE BEGIN SET @InNestedTransaction = 1; END; >代替简单的COMMIT,执行: IF (@@TRANCOUNT > 0 AND @InNestedTransaction = 0) BEGIN COMMIT; END; >代替简单的ROLLBACK,执行: IF (@@TRANCOUNT > 0 AND @InNestedTransaction = 0) BEGIN ROLLBACK; END; 无论事务是在SQL Server中启动还是在应用层启动,此方法都应该相同. 有关TRY … CATCH结构中此事务处理的完整模板,请参阅以下DBA.SE问题的答案:Are we required to handle Transaction in C# Code as well as in stored procedure. 超越“基础”,还需要注意一些额外的交易细微差别: >默认情况下,大多数情况下,发生错误时,事务不会自动回滚/取消.只要您有适当的错误处理并自己调用ROLLBACK,这通常不是问题.但是,有时事情变得复杂,例如在批量中止错误的情况下,或者在使用OPENQUERY(或一般的链接服务器)时,并且远程系统上发生错误.虽然大多数错误都可以使用TRY … CATCH来捕获,但是有两个错误不能被捕获(不记得当前哪些错误 – 研究).在这些情况下,必须使用SET XACT_ABORT ON才能正确回滚事务. SET XACT_ABORT ON使SQL Server立即回滚任何事务(如果一个处于活动状态)并在发生任何错误时中止批处理.此设置存在于SQL Server 2005之前,它引入了TRY … CATCH构造.在大多数情况下,TRY … CATCH处理大多数情况,因此大多数都废弃了对XACT_ABORT ON的需求.但是,当使用OPENQUERY(可能还有一个我目前不记得的场景)时,您仍然需要使用SET XACT_ABORT ON;. 然而,TRY …… CATCH引入了一个新的“状态”.当不使用TRY … CATCH构造时,如果您有一个活动的事务并且发生错误,那么可以采用几个路径: > XACT_ABORT OFF和语句中止错误:事务仍处于活动状态,并继续处理下一个语句(如果有). 但是,当使用TRY … CATCH时,批量中止错误不会中止批处理,而是将控制转移到CATCH块.当XACT_ABORT为OFF时,交易在绝大多数时间内仍然处于活动状态,您需要COMMIT,或者很可能需要ROLLBACK.但是当遇到某些批量中止错误(例如使用OPENQUERY)或XACT_ABORT为ON时,事务将处于新状态,“不可拒绝”.在这种状态下你不能COMMIT,也不能做任何DML操作.您所能做的就是ROLLBACK和SELECT语句.但是,在这种“不可注册”状态下,事务在发生错误时回滚,并且发出ROLLBACK只是一种形式,但必须完成. (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
