Where to Put Error Handling and ROLLBACK TRANSACTION in a TRY/CATCH Block

  • What kind of errors can ROLLBACK TRANSACTION raise? Are these errors typical of something catastrophic that is (or at least should be) well beyond the scope of reporting back to the end user in an application? I'm asking because I would like to know which architecture of code below is more robust:

    1)

    BEGIN TRANSACTION

    BEGIN TRY

    -- Stuff

    COMMIT TRANSACTION

    END TRY

    BEGIN CATCH

    EXEC [dbo].[dba_Error_Handler] @isDynamicSQL = 0

    ROLLBACK TRANSACTION

    END CATCH

    or

    2)

    BEGIN TRANSACTION

    BEGIN TRY

    -- Stuff

    COMMIT TRANSACTION

    END TRY

    BEGIN CATCH

    ROLLBACK TRANSACTION

    EXEC [dbo].[dba_Error_Handler] @isDynamicSQL = 0

    END CATCH

    This code will be run on both SQL Server 2005 and SQL Server 2008 installations.

    My implementation of dba_Error_Handler can be found here. Basically it handles some logic and then reraises the error.

    Thank you.

  • IMHO, the ROLLBACK statement should be the first instruction in the CATCH block, because the RAISERROR in the error handling procedure would prevent any subsequent statement from executing, if called from an external TRY/CATCH block.

    Example:

    CREATE PROCEDURE testError

    AS

    BEGIN

    BEGIN TRANSACTION

    BEGIN TRY

    -- Stuff

    COMMIT TRANSACTION

    END TRY

    BEGIN CATCH

    EXEC [dbo].[dba_Error_Handler] @isDynamicSQL = 0

    ROLLBACK TRANSACTION

    END CATCH

    END

    CREATE PROCEDURE testError2

    AS

    BEGIN

    BEGIN TRY

    EXEC testError

    END TRY

    BEGIN CATCH

    PRINT 'Error occurred'

    PRINT @@Trancount

    END CATCH

    END

    I would also check if a transaction is already in place with @@trancount and either nest a new one (SAVE TRANSACTION) or prevent a new one from starting.

    This is my general template for TRY/CATCH and transaction handling in procedures:

    -- =============================================

    -- Author: <Author,,Name>

    -- Create date: <Create Date,,>

    -- Description: <Description,,>

    -- =============================================

    CREATE PROCEDURE <ProcedureName, sysname, >

    AS

    BEGIN

    DECLARE @localTran bit

    IF @@TRANCOUNT = 0

    BEGIN

    SET @localTran = 1

    BEGIN TRANSACTION LocalTran

    END

    BEGIN TRY

    --Insert code here

    IF @localTran = 1 AND @@TRANCOUNT > 0

    COMMIT TRAN LocalTran

    END TRY

    BEGIN CATCH

    DECLARE @ErrorMessage NVARCHAR(4000)

    DECLARE @ErrorSeverity INT

    DECLARE @ErrorState INT

    SELECT @ErrorMessage = ERROR_MESSAGE(),

    @ErrorSeverity = ERROR_SEVERITY(),

    @ErrorState = ERROR_STATE()

    IF @localTran = 1 AND @@TRANCOUNT > 0

    ROLLBACK TRAN

    RAISERROR ( @ErrorMessage, @ErrorSeverity, @ErrorState)

    END CATCH

    END

    Hope this helps

    Gianluca

    [/code]

    -- Gianluca Sartori

  • Thanks Gianluca. I was also thinking that the ROLLBACK TRANSACTION should occur first.

Viewing 3 posts - 1 through 2 (of 2 total)

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