if you are careful and use TRY-CATCH around everything, and rollback on errors do you really need to use:
SET XACT_ABORT ON
In other words, is there any error that TRY-CATCH will miss that SET XACT_ABORT ON will handle?
if you are careful and use TRY-CATCH around everything, and rollback on errors do you really need to use:
SET XACT_ABORT ON
In other words, is there any error that TRY-CATCH will miss that SET XACT_ABORT ON will handle?
My understanding is that even if a try catch is used and no rollback statement is used in a catch block, any un-commitable transaction will be rolled back when
XACT_ABORT
is ON.When XACT_ABORT set to OFF in trigger and I call RAISEERROR in trigger body, changes not rolled back.
XACT_ABORT does indeed affect error handling: it will abort the entire batch when an error is encountered, and any code following the line that produced the error (including error checking!) will NEVER execute. There are two exceptions to this behavior: XACT_ABORT is superseded by TRY...CATCH (the CATCH block will always execute, and transactions will NOT be rolled back automatically, only rendered uncommitable), and XACT_ABORT will ignore RAISERROR.
I believe SET XACT_ABORT ON was a requirement when executing distributed transactions.
From the books on line: XACT_ABORT must be set ON for data modification statements in an implicit or explicit transaction against most OLE DB providers, including SQL Server. The only case where this option is not required is if the provider supports nested transactions. For more information, see Distributed Queries and Distributed Transactions.
There is a caveat to blindly always using
SET XACT_ABORT ON
; which burned me recently.i read a convincing argument on StackOverflow that suggested that you should always use
XACT_ABORT ON
. i changed the system to set that option during connect. Except it lead to data corruption and a lot of pain.Except that your "more actions" will no longer be happening in a transaction. Because even though you caught the duplicate key violation, the server is no longer in a transaction:
i've since reversed myself. Never use
SET XACT_ABORT ON
.Edit: People seem to think the issue comes from attempting to call
ROLLBACK TRANSACTION
while not in a transaction. They think the problem can be fixed by not callingROLLBACK
if a transaction is not in progress.Let's use some pseudo-code, with the names changes to protect the NDA:
which is a pedantic way of making this answer more readable; we use
x
to represent eXecution of some SQL statement:XACT_ABORT ON is cool, lets use it
So, that code works. If there is an error that we expect, we handle it and continue. This is called handling the error. If some unknown exception happens (something we did not expect), we
rollback
any transaction that may be in progress.Now lets see if we blindly follow the suggestion that
XACT_ABORT
should always be on:Do you see the corruption that will cause in DoStuff?
DoStuff was correctly written to handle error cases. But the introduction of
XACT_ABORT ON
to the connection will now cause database corruption. For those of you who don't see the bug, lets walk through the code:Code that was written correctly, and works, becomes broken, causes errors, and at worst causes database corruption. All because i turned on
XACT_ABORT ON
.Remember that there are errors that TRY-CATCH will not capture with or without
XACT_ABORT
.However,
SET XACT_ABORT ON
does not affect trapping of errors. It does guarantee that any transaction is rolled back / doomed though. When "OFF", then you still have the choice of commit or rollback (subject to xact_state). This is the main change of behaviour for SQL 2005 forXACT_ABORT
What it also does is remove locks etc if the client command timeout kicks in and the client sends the "abort" directive. Without
SET XACT_ABORT
, locks can remain if the connection remains open. My colleague (an MVP) and I tested this thoroughly at the start of the year.