SQL Server XACT_ABORT with exclusion

后端 未结 3 1307
南旧
南旧 2021-01-21 16:55

I have a larger stored procedure which utilizes several TRY/CATCH blocks in order to catch and log individual errors. I have also wrapped a transaction around the entire content

相关标签:
3条回答
  • 2021-01-21 17:07

    You can try something like below ,which ensures you log the operation.This takes advantage of the fact that table variables dont get rollbacked..

    Psuedo code only to give you idea:

    create table test1
    (
    id int primary key
    )
    
    create table logg
    (
    errmsg varchar(max)
    )
    
    
    
    declare @errmsg varchar(max)
    
    set xact_abort on
    begin try
    begin tran
    insert into test1
    select 1
    
    insert into test1
    select 1
    
    commit
    end try
    
    begin catch
    set @errmsg=ERROR_MESSAGE()
    select @errmsg as "in block"
    if @@trancount>0
    rollback tran
    
    end catch
    set xact_abort off
    
    
    select @errmsg as "after block";
    
    insert into logg
    select @errmsg
    
    
    select * from logg
    
    0 讨论(0)
  • 2021-01-21 17:11

    OK... I was able to solve this using a combination of the great suggestions put forth by Alex and GameisWar, with the addition of the T-SQL GOTO control flow statement.

    The basic ideas was to store the error message in a variable, which survives a rollback, then have the Catch send you to a FAILURE label which will do the following:

    • Rollback the transaction
    • Insert a record into the log table, using the data from the aforementioned variable
    • Exit the stored procedure

    I also use a second GOTO statement to make sure that a successful run will skip over the FAILURE section and commit the transaction.

    Below is a code snippet of what the test SQL looked like. It worked like a charm, and I have already implemented this and tested it (successfully) in our production environment.

    I really appreciate all the help and input!

    SET XACT_ABORT ON               
    DECLARE @MESSAGE VARCHAR(MAX) = '';
    
    BEGIN TRANSACTION 
        BEGIN TRY
            INSERT INTO TEST_TABLE VALUES ('TEST');     -- WORKS FINE
        END TRY 
        BEGIN CATCH     
            SET @MESSAGE = 'ERROR - SECTION 1: ' + ERROR_MESSAGE();
            GOTO FAILURE;
        END CATCH
    
        BEGIN TRY
            INSERT INTO TEST_TABLE VALUES ('TEST2');        --WORKS FINE
            INSERT INTO TEST_TABLE VALUES ('ANOTHER TEST'); -- ERRORS OUT, DATA WOULD BE TRUNCATED
        END TRY 
        BEGIN CATCH 
            SET @MESSAGE = 'ERROR - SECTION 2: ' + ERROR_MESSAGE();
            GOTO FAILURE;
        END CATCH
    
    GOTO SUCCESS;
    
    FAILURE:        
        ROLLBACK
        INSERT INTO LOGG SELECT @MESSAGE
        RETURN; 
    
    SUCCESS:
    COMMIT TRANSACTION
    
    0 讨论(0)
  • 2021-01-21 17:20

    I don't know details but IMHO general logic can be like this.

    --set XACT_ABORT ON --not include it
    declare @result varchar(max) --collect details in case you need it
    begin transaction
    begin try
    --your logic here
    --if something wrong RAISERROR(...@result)
    --everything OK
    commit
    end try
    begin catch
    --collect error_message() and other into @result
    rollback
    end catch
    insert log(result) values (@result)
    
    0 讨论(0)
提交回复
热议问题