Om du har ett TRY/CATCH-block är den troliga orsaken att du fångar ett undantag för att avbryta transaktionen och fortsätter. I CATCH-blocket måste du alltid kontrollera XACT_STATE()
och hantera lämpliga avbrutna och obotliga (dömda) transaktioner. Om din uppringare startar en transaktion och samtalet hamnar i, säg, ett dödläge (som avbröt transaktionen), hur ska den som ringer kommunicera till uppringaren att transaktionen avbröts och att den inte ska fortsätta med "business as usual"? Det enda möjliga sättet är att återuppta ett undantag, vilket tvingar den som ringer att hantera situationen. Om du tyst sväljer en avbruten transaktion och den som ringer fortsätter att anta att den fortfarande är i den ursprungliga transaktionen, kan bara kaos garantera (och felet du får är hur motorn försöker skydda sig själv).
Jag rekommenderar att du går igenom Undantagshantering och kapslade transaktioner som visar ett mönster som kan användas med kapslade transaktioner och undantag:
create procedure [usp_my_procedure_name]
as
begin
set nocount on;
declare @trancount int;
set @trancount = @@trancount;
begin try
if @trancount = 0
begin transaction
else
save transaction usp_my_procedure_name;
-- Do the actual work here
lbexit:
if @trancount = 0
commit;
end try
begin catch
declare @error int, @message varchar(4000), @xstate int;
select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
if @xstate = -1
rollback;
if @xstate = 1 and @trancount = 0
rollback
if @xstate = 1 and @trancount > 0
rollback transaction usp_my_procedure_name;
raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
end catch
end
go