简体   繁体   English

当一般是 raiserror 时如何提交嵌套存储过程

[英]How to commit nested stored procedure, when general is raiserror

I have one stored procedure proc_in which the insert data to tbl table我有一个存储过程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

and I have proc_out where I call proc_in我有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

How I can write proc_out that it return raiserror always to do insert in TBL table.我如何编写proc_out它总是返回raiserror以在TBL表中插入。 I calling proc_out like this我这样调用proc_out

begin tran 
    declare @err int = 0
    exec @err = proc_out
if @ERR = 0 
    commit tran 
else 
    rollback tran

You are wrapping your call in a single transaction in the calling context, therefore:您将调用包装在调用上下文中的单个事务中,因此:

begin tran 
    declare @err int = 0
    exec @err = proc_out
if @ERR = 0 
    commit tran 
else 
    rollback tran

will always roll back everything that has happened within that transaction.将始终回滚该事务中发生的所有事情。

One way to avoid this is to move the transaction inside your 'proc_out' SP eg避免这种情况的一种方法是将事务移动到您的“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;

Alternatively, and I haven't tried this, you could try using a savepoint eg或者,我还没有尝试过,您可以尝试使用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;

Then call it as:然后将其称为:

begin tran;

declare @err int = 0;
exec @err = proc_out;

if @ERR = 0;
    commit tran;
end; else begin
    rollback tran SavePoint1;
    commit tran;
end;

I don't like this approach though, because knowledge of the inner workings of your SP has now leaked out to the calling context.不过我不喜欢这种方法,因为您的 SP 内部工作原理的知识现在已经泄露到调用上下文中。

And some errors will roll back the entire transaction regardless.无论如何,一些错误将回滚整个事务。

Its important to be aware of the XACT_ABORT setting here.了解此处的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.当 SET XACT_ABORT 为 OFF 时,在某些情况下,只有引发错误的 Transact-SQL 语句被回滚,事务继续处理。 Depending upon the severity of the error, the entire transaction may be rolled back even when SET XACT_ABORT is OFF.根据错误的严重程度,即使 SET XACT_ABORT 为 OFF,也可能回滚整个事务。 OFF is the default setting in a T-SQL statement, while ON is the default setting in a trigger. OFF 是 T-SQL 语句中的默认设置,而 ON 是触发器中的默认设置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM