一种在调用可能调用其他 SP 的 SP 时保持 XACT_ABORT 开启并获取错误(如果有)或提交(如果一切正常)的方法:例如两个 sp 和三个测试
create PROCEDURE [dbo].[myTestProcCalled]
(
@testin int=0
)
as
begin
declare @InnerTrans int
set XACT_ABORT on;
set @InnerTrans = @@trancount;
PRINT '02_01_Trancount='+cast (@InnerTrans as varchar(2));
begin try
if (@InnerTrans = 0)
begin
PRINT '02_02_beginning trans';
begin transaction
end
declare @t2 int
set @t2=0
PRINT '02_03_doing division'
set @t2=10/@testin
PRINT '02_04_doing AfterStuff'
if (@InnerTrans = 0 and XACT_STATE()=1)
begin
PRINT '02_05_Committing'
commit transaction
end
PRINT '02_05B_selecting calledValue=' +cast(@t2 as varchar(20))
select @t2 as insidevalue
end try
begin catch
PRINT '02_06_Catching Errors from called'
declare @ErrorMessage nvarchar(4000);
declare @ErrorNumber int;
declare @ErrorSeverity int;
declare @ErrorState int;
select @ErrorMessage = error_message(), @ErrorNumber = error_number(), @ErrorSeverity = error_severity(), @ErrorState = error_state();
if (@InnerTrans = 0 and XACT_STATE()=-1)
begin
PRINT '02_07_Rolbacking'
rollback transaction
end
PRINT '02_08_Rising Error'
raiserror(@ErrorMessage, @ErrorSeverity, @ErrorState);
--use throw if in 2012 or above
-- else might add a "return" statement
end catch
end
go
create PROCEDURE [dbo].[myTestPCalling]
(
@test int=0
,@testinside int=0
)
as
begin
declare @InnerTrans int
set XACT_ABORT on;
set @InnerTrans = @@trancount;
PRINT '01_01_Trancount='+cast (@InnerTrans as varchar(2));
begin try
if (@InnerTrans = 0)
begin
PRINT '01_02_beginning trans';
begin transaction
end
declare @t2 int
set @t2=0
PRINT '01_03_doing division'
set @t2=10/@test
PRINT '01_04_calling inside sp'
execute [dbo].[myTestProcCalled]
@testin = @testinside
--
PRINT '01_05_doing AfterStuff'
if (@InnerTrans = 0 and XACT_STATE()=1)
begin
PRINT '01_06_Committing'
commit transaction
PRINT '01_06B_selecting callerValue=' +cast(@t2 as varchar(20))
select @t2 as outsidevalue
end
end try
begin catch
PRINT '01_07_Catching Errors from Caller'
declare @ErrorMessage nvarchar(4000);
declare @ErrorNumber int;
declare @ErrorSeverity int;
declare @ErrorState int;
select @ErrorMessage = error_message(), @ErrorNumber = error_number(), @ErrorSeverity = error_severity(), @ErrorState = error_state();
if (@InnerTrans = 0 and XACT_STATE()=-1)
begin
PRINT '01_08_Rolbacking'
rollback transaction
end
PRINT '01_09_Rising Error'
raiserror(@ErrorMessage, @ErrorSeverity, @ErrorState);
--use throw if in 2012 or above
-- else might add a "return" statement
end catch
end
----test 1 :result OK----
USE [PRO-CGWEB]
GO
DECLARE @return_value int
EXEC @return_value = [dbo].[myTestPCalling]
@test =2
,@testinside = 2
SELECT 'Return Value' = @return_value
GO
----test2 :error in caller ----
USE [PRO-CGWEB]
GO
DECLARE @return_value int
EXEC @return_value = [dbo].[myTestPCalling]
@test =0
,@testinside = 2
SELECT 'Return Value' = @return_value
GO
----test3 :error in calling ----
USE [PRO-CGWEB]
GO
DECLARE @return_value int
EXEC @return_value = [dbo].[myTestPCalling]
@test =2
,@testinside = 0
SELECT 'Return Value' = @return_value
GO