general 为 raiserror 时如何提交嵌套存储过程
How to commit nested stored procedure, when general is raiserror
我有一个存储过程 proc_in
将数据插入 tbl
table
create table tbl(id int identity, val nvarchar(50))
create procedure proc_in
as
begin
insert into tbl(val)
values ('test')
end
我有 proc_out
,我打电话给 proc_in
create procedure proc_out
as
begin
exec proc_in
DECLARE @MessageText NVARCHAR(100);
SET @MessageText = N'This is a raiserror %s';
RAISERROR(@MessageText, 16, 1, N'MSG')
end
我怎么写 proc_out
它 return raiserror
总是插入 TBL
table。
我这样调用 proc_out
begin tran
declare @err int = 0
exec @err = proc_out
if @ERR = 0
commit tran
else
rollback tran
您将调用包装在调用上下文中的单个事务中,因此:
begin tran
declare @err int = 0
exec @err = proc_out
if @ERR = 0
commit tran
else
rollback tran
将始终回滚该事务中发生的所有内容。
避免这种情况的一种方法是将交易移动到您的 'proc_out' SP 中,例如
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
设置很重要。
When SET XACT_ABORT is OFF, in some cases only the Transact-SQL statement that raised the error is rolled back and the transaction continues processing. Depending upon the severity of the error, the entire transaction may be rolled back even when SET XACT_ABORT is OFF. OFF is the default setting in a T-SQL statement, while ON is the default setting in a trigger.
我有一个存储过程 proc_in
将数据插入 tbl
table
create table tbl(id int identity, val nvarchar(50))
create procedure proc_in
as
begin
insert into tbl(val)
values ('test')
end
我有 proc_out
,我打电话给 proc_in
create procedure proc_out
as
begin
exec proc_in
DECLARE @MessageText NVARCHAR(100);
SET @MessageText = N'This is a raiserror %s';
RAISERROR(@MessageText, 16, 1, N'MSG')
end
我怎么写 proc_out
它 return raiserror
总是插入 TBL
table。
我这样调用 proc_out
begin tran
declare @err int = 0
exec @err = proc_out
if @ERR = 0
commit tran
else
rollback tran
您将调用包装在调用上下文中的单个事务中,因此:
begin tran
declare @err int = 0
exec @err = proc_out
if @ERR = 0
commit tran
else
rollback tran
将始终回滚该事务中发生的所有内容。
避免这种情况的一种方法是将交易移动到您的 'proc_out' SP 中,例如
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
设置很重要。
When SET XACT_ABORT is OFF, in some cases only the Transact-SQL statement that raised the error is rolled back and the transaction continues processing. Depending upon the severity of the error, the entire transaction may be rolled back even when SET XACT_ABORT is OFF. OFF is the default setting in a T-SQL statement, while ON is the default setting in a trigger.