简体   繁体   中英

SQL Server TRY…CATCH with XACT_STATE

I have a question regarding the MSDN documentation for TRY CATCH blocks. Check out this article and scroll down to Example C "Using TRY…CATCH with XACT_STATE"

http://msdn.microsoft.com/en-us/library/ms175976.aspx

The example first places a COMMIT TRANSACTION within the Try block, and then places a second one in the Catch block if XACT_STATE()=1 .

However I thought a Catch block will only execute in case of an error. So how could both the Catch block execute and XACT_STATE return 1? That seems contradictory.

There is an unanswered comment within the XACT_STATE documentation which asks this same question

http://msdn.microsoft.com/en-us/library/ms189797.aspx

@user1181412 My analysis is as follows: This comment:

-- A FOREIGN KEY constraint exists on this table.

--This statement will generate a constraint violation error

is the answer to your question. What is happening is that when the DELETE statement executes, it generates a constraint violation error and the subsequent COMMIT does not execute. The XACT_STATE of the transaction is now 1 and the CATCH block is executing.

At the top, you have

SET XACT_ABORT ON;

This causes the transaction state to be uncommittable and hence this code block will rollback the transaction:

-- Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
    PRINT
        N'The transaction is in an uncommittable state.' +
        'Rolling back transaction.'
    ROLLBACK TRANSACTION;
END;

However, if you change to "SET XACT_ABORT OFF;" then the CATCH block would be hit albeit the transaction state will be "committable" as XACT_STATE = 1 .

NOTE: Delete would still not be done as the constraint violation is still there, but you would see this printed:

(1 row(s) affected) The transaction is committable.Committing transaction.

XACT_STATE is a function that returns to the user the state of a running transaction.
XACT_STATE indicates whether the request has an active user transaction, and whether the transaction is capable of being committed or not.

(Keep in mind that usually errors happen on update / insert and not on select queries).


There are 3 status of XACT_STATE :

1 : query inside the Transaction block is active and valid (didn't throw an error).
0 : The query will not throw an error (for example ,a select query inside transaction without update/insert queries).
-1 : The query inside transaction threw an error (when entering the catch block) and will do a complete rollback (if we have 4 succeeded queries and 1 throw an error , all the 5 queries will roll back ).

Example :

    BEGIN TRY    
    BEGIN TRANSACTION;
        -- A FOREIGN KEY constraint exists on this table.  
        -- This statement will generate a constraint violation error.
        DELETE FROM Production.Product
            WHERE ProductID = 980;

    -- If the delete operation succeeds, commit the transaction. The CATCH
    -- block will not execute.
    COMMIT TRANSACTION; 
    END TRY
    BEGIN CATCH
    -- Test XACT_STATE for 0, 1, or -1.

    -- Test whether the transaction is uncommittable.
    IF (XACT_STATE()) = -1
    BEGIN
        PRINT 'The transaction is in an uncommittable state.' +
              ' Rolling back transaction.'
        ROLLBACK TRANSACTION;
    END;

    -- Test whether the transaction is active and valid.
    IF (XACT_STATE()) = 1
    BEGIN
        PRINT 'The transaction is committable.' + 
              ' Committing transaction.'
        COMMIT TRANSACTION;   
    END;
    END CATCH

References :
https://docs.microsoft.com/en-us/sql/t-sql/functions/xact-state-transact-sql http://www.advancesharp.com/blog/1017/sql-transaction-status-and-xact-state

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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