Вы оборачиваете свой вызов в одну транзакцию в контексте вызова, поэтому:
begin tran
declare @err int = 0
exec @err = proc_out
if @ERR = 0
commit tran
else
rollback tran
всегда будет откатывать все, что произошло в этой транзакции.
Один из способов избежать этого - переместить транзакцию внутри вашего SP 'proc_out', например.
create procedure proc_out
as
begin
set nocount, xact_abort on;
exec proc_in;
begin tran;
-- All your other code
if @Err = 1 begin
rollback;
declare @MessageText nvarchar(100);
set @MessageText = N'This is a raiserror %s';
--raiserror(@MessageText, 16, 1, N'MSG');
-- Actually for most cases now its recommended to use throw
throw 51000, @MessageText 1;
end; else begin
commit;
end;
return 0;
end;
В качестве альтернативы, и я этого не пробовал, вы можете попробовать использовать savepoint
, например.
create procedure proc_out
as
begin
set nocount on;
exec proc_in;
save transaction SavePoint1;
declare @MessageText nvarchar(100);
set @MessageText = N'This is a raiserror %s';
raiserror(@MessageText, 16, 1, N'MSG');
return 0;
end;
Затем назовите это как:
begin tran;
declare @err int = 0;
exec @err = proc_out;
if @ERR = 0;
commit tran;
end; else begin
rollback tran SavePoint1;
commit tran;
end;
Однако мне не нравится такой подход, потому что информация о внутренней работе вашего SP теперь просочилась в вызывающий контекст.
И некоторые ошибки независимо откатят всю транзакцию.
Важно знать о XACT_ABORT
.
Когда SET XACT_ABORT имеет значение OFF, в некоторых случаях выполняется откат только инструкции Transact-SQL, вызвавшей ошибку, и транзакция продолжает обработку. В зависимости от серьезности ошибки вся транзакция может быть отменена, даже если SET XACT_ABORT выключен. OFF — это параметр по умолчанию в инструкции T-SQL, а ON — параметр по умолчанию в триггере.
person
Dale K
schedule
03.02.2021