Try catch in a transaction block or transaction in try catch block???

  • Simple task -

    Perform a few inserts or updates on multiple tables in the same database. If there is an error in any one of the inserts or updates, rollback all the changes.

    My question is which one is apt or works better.

    1-----------------------------------------------------------------------------------------------------------------

    Begin Tran

    Begin Try

    Insert

    Insert

    Update

    Update

    Commit Tran

    End Try

    Begin Catch

    IF @@TRANCOUNT > 0

    ROLLBACK

    -- Raise an error with the details of the exception

    DECLARE @ErrMsg nvarchar(4000), @ErrSeverity int

    SELECT @ErrMsg = ERROR_MESSAGE(),

    @ErrSeverity = ERROR_SEVERITY()

    RAISERROR(@ErrMsg, @ErrSeverity, 1)

    End Catch

    ------------------------------------------------------OR--------------------------------------------------------

    2-----------------------------------------------------------------------------------------------------------------

    BEGIN TRY

    BEGIN TRANSACTION;

    Insert

    Insert

    Update

    Update

    COMMIT TRANSACTION;

    END TRY

    BEGIN CATCH

    -- Roll back any active or uncommittable transactions

    IF XACT_STATE() <> 0

    BEGIN

    ROLLBACK TRANSACTION;

    END

    DECLARE @ErrMsg nvarchar(4000), @ErrSeverity int

    SELECT @ErrMsg = ERROR_MESSAGE(),

    @ErrSeverity = ERROR_SEVERITY()

    RAISERROR(@ErrMsg, @ErrSeverity, 1)

    END CATCH

  • You can use my stored procedure code template[/url] if you like it.

    It should do what you ask for.

    Regards

    Gianluca

    -- Gianluca Sartori

  • Hi Gianluca,

    Have a question about this code:

    IF @localTran = 1 AND XACT_STATE() = 1

    ROLLBACK TRAN

    Once you're in the catch block, wouldn't you want to roll back the transaction regardless of whether the transaction was commitable or not?

    Apologies if I'm missing something.

  • krishna.vanne (9/22/2011)


    My question is which one is apt or works better.

    It really doesn't make a difference.

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • HowardW (9/23/2011)


    Hi Gianluca,

    Have a question about this code:

    IF @localTran = 1 AND XACT_STATE() = 1

    ROLLBACK TRAN

    Once you're in the catch block, wouldn't you want to roll back the transaction regardless of whether the transaction was commitable or not?

    Apologies if I'm missing something.

    You're right!

    It should be:

    IF @localTran = 1 AND XACT_STATE() <> 0

    ROLLBACK TRAN

    Edited: I guess I didnt' have enough sleep tonight.

    -- Gianluca Sartori

  • try this ...

    Begin Try

    Begin Tran

    Insert Into TableName Values (99, 'ZZZ');

    Update TableName

    SetColName = 'XXX'

    Where ColName = 99;

    Commit Tran

    End Try

    Begin Catch

    If @@Error <> 0

    Begin

    RollBack Tran

    End

    End Catch

    MH-09-AM-8694

  • Mahesh Bote (9/23/2011)


    try this ...

    Begin Try

    Begin Tran

    Insert Into TableName Values (99, 'ZZZ');

    Update TableName

    SetColName = 'XXX'

    Where ColName = 99;

    Commit Tran

    End Try

    Begin Catch

    If @@Error <> 0

    Begin

    RollBack Tran

    End

    End Catch

    If you fall into the catch block @@Error must be other than 0.

    Am I missing something?

    -- Gianluca Sartori

  • krishna.vanne (9/22/2011)


    My question is which one is apt or works better.

    It's a question of style. My personal preference is to start the transaction inside the TRY (option 2) just because it feels neater to me to have all the transaction-related stuff in the same 'block'.

    I also like to SET XACT_ABORT ON to minimize the chances of leaving a hanging transaction. Error handling is annoyingly quirky and imperfect in T-SQL, sad to say.

  • SQL Kiwi (9/23/2011)


    krishna.vanne (9/22/2011)


    My question is which one is apt or works better.

    It's a question of style. My personal preference is to start the transaction inside the TRY (option 2) just because it feels neater to me to have all the transaction-related stuff in the same 'block'.

    I also like to SET XACT_ABORT ON to minimize the chances of leaving a hanging transaction. Error handling is annoyingly quirky and imperfect in T-SQL, sad to say.

    Agreed. My personal preference is option 1 instead.

    In java and c# you generally begin the transaction outside the try block, so that you are sure that if you fall into the catch block the transaction is open and you can rollback (unless the connection was forcibly closed). I got accustomed to this style and I kept it in T-SQL.

    -- Gianluca Sartori

  • Books Online states that

    Although BEGIN TRANSACTION starts a local transaction, it is not recorded in the transaction log until the application subsequently performs an action that must be recorded in the log, such as executing an INSERT, UPDATE, or DELETE statement. An application can perform actions such as acquiring locks to protect the transaction isolation level of SELECT statements, but nothing is recorded in the log until the application performs a modification action.

    In other words, the first recording of the transaction in the log is when the first insert/update/delete is executed after the begin transaction statement for that transaction. SO as was stated before, it doesn't matter whether you put the begin transaction or the begin try first. I do have a personal preference of putting the begin transaction before the begin try, just so that -if ever- the begin transaction could fail, execution would not be passed into the catch block with an uninitialised transaction, but would fail outside the try block instead. But, as said, this is a theoretical difference only, as "begin transaction" can not fail is commonly believed never to fail.

    I do have a remark on using "SET XACT_ABORT ON", though. ON is better only used when no error handling is in place. When xact_abort is OFF execution will still upon an error go straight into the catch block. The only thing that xact_abort ON does is make the engine decide to abort your code faster. This violates the intent of the try-catch construct as it bypasses the catch block in situations where xact_abort on kicks in. In fact, xact_abort ON makes the engine behave more "sensitive" to errors. For any errors that did not cause the procedure to be aborted early, the transaction will have been doomed (i.e. xact_state() = -1). To minimise the number of situations in which the engine will choose to abort my procedures and to avoid transactions becoming doomed I explicitly set xact_abort to OFF inside each procedure and test for xact_state() inside each catch block. Sadly, even with xact_abort set to OFF some errors will still return execution to the caller or doom the transaction. This will break the proper operation of any procedure that tries to "play nice" in any situation where an enclosing transaction may or may not be provided.

    Here's an example of an sp that tries to properly handle errors in every possible situation. It demonstrates various errors and the difference that xact_abort makes on them. I do a lot of work on SQL server service broker handlers, which need a transaction around the entire operation. This sort of "broken" error handling makes writing these handlers very hard...

    First a little scripting to set up a test table and procedure in your tempdb:

    use tempdb;

    go

    create table dbo.Test (

    id int not null,

    x xml null,

    primary key (id)

    );

    go

    create procedure dbo.spTest( @error int, @xa_on int = 0)

    as

    begin

    declare @result int = 0;

    set nocount on;

    if @xa_on = 1

    set xact_abort on;

    else

    set xact_abort off;

    declare @trancount int;

    select @trancount = @@trancount;

    if @trancount > 0

    save transaction trnMyTran;

    else

    begin transaction trnMyTran;

    begin try

    -- Do something.

    if @error = 1

    begin

    -- This creates a divide by zero error

    -- which can be properly handled.

    insert dbo.Test(id)

    select @error/0;

    end else if @error = 2

    begin

    -- This creates a doomed transaction (in fact: just assigning

    -- the invalid xml to a local variable is sufficient to doom

    -- the transaction!). This one is VERY annoying and I can not

    -- find a way to avoid it.

    declare @xml xml;

    insert dbo.Test(id, x)

    select @error, N'<some_invalid_xml>';

    end else if @error = 3

    begin

    -- Primary key violation

    insert dbo.Test(id)

    select @error

    union all select @error

    end else

    begin

    -- merge the @id into the table, updating x to some

    -- xml value.

    with cte as (

    select t.id, t.x

    from dbo.Test t

    where t.id = @error

    )

    merge cte trg

    using (

    select @error as id,

    (

    select @error as [@error],

    getutcdate() as [@date]

    for xml path('test'), type

    ) x

    ) src

    on (trg.id = src.id)

    when not matched then

    insert (id, x)

    values(src.id, src.x)

    when matched then

    update

    set x = src.x;

    end

    print 'Just before the commit (i.e. execution has not been transferred into the catch block).'

    if not @trancount > 0

    commit tran trnMyTran;

    end try

    begin catch

    select error_number(), error_message();

    if xact_state() > 0

    rollback tran trnMyTran;

    else if not @trancount > 0 and xact_state() < 0

    rollback tran;

    select @result = 50000;

    end catch

    return @result;

    end

    go

    Now do some tests using this procedure. Especially note the results for xact_state(): 1 = in a valid transaction, 0 = not in a transaction, -1 = in an invalid (doomed) transaction, i.e.: you're in trouble :(.

    print '=============== No error, xact_abort OFF ============'

    -- Show that spTest "plays nice" when no error occurs:

    begin tran trnTest;

    declare @nResult int;

    exec @nResult = dbo.spTest 0, 0;

    select @nResult as result, @@trancount as [trancount], xact_state() as [xact_state];

    if xact_state() > 0

    commit tran trnTest;

    else if xact_state() < 0

    rollback tran;

    go

    print '=============== Divide by Zero error, xact_abort OFF ============'

    -- Now try 'divide by zero error' with "set xact_abort off".

    -- result: Transaction is ok, caller can decide how to continue.

    begin tran trnTest;

    declare @nResult int;

    exec @nResult = dbo.spTest 1, 0;

    select @nResult as result, @@trancount as [trancount], xact_state() as [xact_state];

    if xact_state() > 0

    commit tran trnTest;

    else if xact_state() < 0

    rollback tran;

    go

    print '=============== Divide by Zero error, xact_abort ON ============'

    -- Do the same 'divide by zero error' but with "set xact_abort on".

    -- Result: Transaction is doomed, caller has not choice to abort or another error is thrown.

    begin tran trnTest;

    declare @nResult int;

    exec @nResult = dbo.spTest 1, 1;

    select @nResult as result, @@trancount as [trancount], xact_state() as [xact_state];

    if xact_state() > 0

    commit tran trnTest;

    else if xact_state() < 0

    rollback tran;

    go

    print '=============== primary key violation error, xact_abort OFF ============'

    -- Try 'primary key violation error' with "set xact_abort off".

    -- result: Transaction is ok. Caller can decide how to continue.

    begin tran trnTest;

    declare @nResult int;

    exec @nResult = dbo.spTest 3, 0;

    select @nResult as result, @@trancount as [trancount], xact_state() as [xact_state];

    if xact_state() > 0

    commit tran trnTest;

    else if xact_state() < 0

    rollback tran;

    go

    print '=============== primary key violation error, xact_abort ON ============'

    -- Same 'primary key violation error' again but now with "set xact_abort on".

    -- result: Transaction is doomed. Caller has no choice but to rollback.

    begin tran trnTest;

    declare @nResult int;

    exec @nResult = dbo.spTest 3, 1;

    select @nResult as result, @@trancount as [trancount], xact_state() as [xact_state];

    if xact_state() > 0

    commit tran trnTest;

    else if xact_state() < 0

    rollback tran;

    go

    print '=============== XML parsing error, xact_abort OFF ============'

    -- Xml parsing error is a serious problem, it can not be properly handled!

    -- Try 'xml parsing error' with "set xact_abort off".

    -- result: Transaction is doomed. Caller has to rollback.

    begin tran trnTest;

    declare @nResult int;

    exec @nResult = dbo.spTest 2, 0;

    select @nResult as result, @@trancount as [trancount], xact_state() as [xact_state];

    if xact_state() > 0

    commit tran trnTest;

    else if xact_state() < 0

    rollback tran;

    go

    print '=============== XML parsing error, xact_abort ON ============'

    -- Same 'xml parsing error' again but now with "set xact_abort on".

    -- result: Transaction is still doomed. Caller has to rollback here too.

    begin tran trnTest;

    declare @nResult int;

    exec @nResult = dbo.spTest 2, 1;

    select @nResult as result, @@trancount as [trancount], xact_state() as [xact_state];

    if xact_state() > 0

    commit tran trnTest;

    else if xact_state() < 0

    rollback tran;

    go

    output:

    =============== No error, xact_abort OFF ============

    Just before the commit (i.e. execution has not been transferred into the catch block).

    result trancount xact_state

    ----------- ----------- ----------

    0 1 1

    (1 row(s) affected)

    =============== Divide by Zero error, xact_abort OFF ============

    ----------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    8134 Divide by zero error encountered.

    result trancount xact_state

    ----------- ----------- ----------

    50000 1 1

    (1 row(s) affected)

    =============== Divide by Zero error, xact_abort ON ============

    ----------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    8134 Divide by zero error encountered.

    result trancount xact_state

    ----------- ----------- ----------

    50000 1 -1

    (1 row(s) affected)

    =============== primary key violation error, xact_abort OFF ============

    ----------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    2627 Violation of PRIMARY KEY constraint 'PK__Test__3213E83F108B050B'. Cannot insert duplicate key in object 'dbo.Test'.

    result trancount xact_state

    ----------- ----------- ----------

    50000 1 1

    (1 row(s) affected)

    =============== primary key violation error, xact_abort ON ============

    ----------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    2627 Violation of PRIMARY KEY constraint 'PK__Test__3213E83F108B050B'. Cannot insert duplicate key in object 'dbo.Test'.

    result trancount xact_state

    ----------- ----------- ----------

    50000 1 -1

    (1 row(s) affected)

    =============== XML parsing error, xact_abort OFF ============

    ----------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    9400 XML parsing: line 1, character 18, unexpected end of input

    result trancount xact_state

    ----------- ----------- ----------

    50000 1 -1

    (1 row(s) affected)

    =============== XML parsing error, xact_abort ON ============

    ----------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    9400 XML parsing: line 1, character 18, unexpected end of input

    result trancount xact_state

    ----------- ----------- ----------

    50000 1 -1

    (1 row(s) affected)

    And finally, cleanup after the experiments:

    drop table dbo.Test;

    drop procedure dbo.spTest;

    I hope this helps any of you in properly handling errors. And maybe you'll reconsider using xact_abort ON.

    edit:

    - added print to demonstrate execution is passed into the catch block.

    - added output.



    Posting Data Etiquette - Jeff Moden[/url]
    Posting Performance Based Questions - Gail Shaw[/url]
    Hidden RBAR - Jeff Moden[/url]
    Cross Tabs and Pivots - Jeff Moden[/url]
    Catch-all queries - Gail Shaw[/url]


    If you don't have time to do it right, when will you have time to do it over?

  • Thanks all for your wonderful post and explanations. Really helpful.

  • R.P.Rozema (9/23/2011)


    So as was stated before, it doesn't matter whether you put the begin transaction or the begin try first. I do have a personal preference of putting the begin transaction before the begin try, just so that -if ever- the begin transaction could fail, execution would not be passed into the catch block with an uninitialised transaction, but would fail outside the try block instead. But, as said, this is a theoretical difference only, as "begin transaction" can not fail is commonly believed never to fail.

    Yes either way is fine. Not sure what you mean by 'uninitialised transaction' though - either a transaction gets started, or it doesn't. Any sane CATCH block has to be coded for the case when XACT_STATE() = 0.

    I do have a remark on using "SET XACT_ABORT ON", though. ON is better only used when no error handling is in place.

    In general, what passes for error handling in T-SQL is at least a bit more predictable with XACT_ABORT ON. There are still some edge cases that behave counter-intuitively (some for backward compatibility!) but not so many as with XACT_ABORT OFF. It is clear you particular needs and working with it OFF suits you better - and that's fine - but many/most people will find ON a better option overall.

  • SQL Kiwi (9/23/2011)Yes either way is fine. Not sure what you mean by 'uninitialised transaction' though - either a transaction gets started, or it doesn't. Any sane CATCH block has to be coded for the case when XACT_STATE() = 0.

    An 'uninitialised transaction' would be whatever the result can be of a failed call to "begin transaction". In a perfect world you are right, a transaction get started or it doesn't. But that's exactly my point here: if "begin transaction" fails, will the transaction state be consistent? Since "begin transaction" failed, we can't be sure.

    In general, what passes for error handling in T-SQL is at least a bit more predictable with XACT_ABORT ON. There are still some edge cases that behave counter-intuitively (some for backward compatibility!) but not so many as with XACT_ABORT OFF. It is clear you particular needs and working with it OFF suits you better - and that's fine - but many/most people will find ON a better option overall.

    I agree, if you don't implement error handling using a try-catch block, you best set xact_abort to ON to avoid having pieces of your code executed with unknown input(s). However having it with a try-catch block in place does not serve a purpose; execution is diverted into the catch block upon the first occurrence of an error, so the code following the statement that raised the error is not executed, just like with set xact_abort ON. However xact_abort ON does have this nasty side effect on your transactions which is best avoided, since many people don't even know about the existence of uncommitable transactions, let alone how to deal with them.

    edit: incorrect quoting fixed



    Posting Data Etiquette - Jeff Moden[/url]
    Posting Performance Based Questions - Gail Shaw[/url]
    Hidden RBAR - Jeff Moden[/url]
    Cross Tabs and Pivots - Jeff Moden[/url]
    Catch-all queries - Gail Shaw[/url]


    If you don't have time to do it right, when will you have time to do it over?

  • B.T.W. I have created a connect item for the fact that assigning an invalid xml invalidates the transaction, even on an unlogged action. I would appreciate any votes for it: https://connect.microsoft.com/SQLServer/feedback/details/690463/error-9400-and-other-xml-parsing-errors-should-not-make-transaction-uncommittable



    Posting Data Etiquette - Jeff Moden[/url]
    Posting Performance Based Questions - Gail Shaw[/url]
    Hidden RBAR - Jeff Moden[/url]
    Cross Tabs and Pivots - Jeff Moden[/url]
    Catch-all queries - Gail Shaw[/url]


    If you don't have time to do it right, when will you have time to do it over?

  • R.P.Rozema (9/23/2011)


    In a perfect world you are right, a transaction get started or it doesn't. But that's exactly my point here: if "begin transaction" fails, will the transaction state be consistent? Since "begin transaction" failed, we can't be sure.

    Hah. Well I'm all for defensive programming, but you might as well worry about what happens if the BEGIN TRY fails and leaves you with an open transaction. Seriously, I wouldn't worry about SQL Server failing to begin a transaction leaving you in some weird netherworld.

    I agree, if you don't implement error handling using a try-catch block, you best set xact_abort to ON to avoid having pieces of your code executed with unknown input(s). However having it with a try-catch block in place does not serve a purpose; execution is diverted into the catch block upon the first occurrence of an error, so the code following the statement that raised the error is not executed, just like with set xact_abort ON.

    Of course there's a purpose - you might need to clean up some non-transaction resources, log some error details somewhere, and so on. I wish it were true that errors always diverted into the CATCH block, but you can't rely on this. The following snippet illustrates a very common scenario where the CATCH won't be called:

    CREATE PROCEDURE #BreakMe

    AS

    BEGIN

    SET XACT_ABORT OFF

    BEGIN TRANSACTION

    BEGIN TRY

    -- Simulate some processing

    WAITFOR DELAY '00:01:00'

    COMMIT TRANSACTION

    END TRY

    BEGIN CATCH

    IF XACT_STATE() <> 0 ROLLBACK TRANSACTION

    PRINT 'Oh dear, an error'

    END CATCH

    END

    -- Run this, and hit Cancel Executing Query in SSMS

    -- while it is running

    EXECUTE #BreakMe

    -- Catch not executed, no message, trancount = 1

    PRINT @@TRANCOUNT

    -- You'll need to execute this

    ROLLBACK

    GO

    DROP PROC #BreakMe

    Notice that this leaves you with a silently-open transaction in SSMS. XACT_ABORT ON protects you from this. Any attention signal from the client causes this behaviour (including an ordinary query timeout). There are all sorts of weird and annoying quirks like this.

Viewing 15 posts - 1 through 15 (of 32 total)

You must be logged in to reply to this topic. Login to reply