[英]How to commit nested stored procedure, when general is raiserror
我有一个存储过程proc_in
将数据插入tbl
表
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
它总是返回raiserror
以在TBL
表中插入。 我这样调用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
设置很重要。
当 SET XACT_ABORT 为 OFF 时,在某些情况下,只有引发错误的 Transact-SQL 语句被回滚,事务继续处理。 根据错误的严重程度,即使 SET XACT_ABORT 为 OFF,也可能回滚整个事务。 OFF 是 T-SQL 语句中的默认设置,而 ON 是触发器中的默认设置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.