4

I have the process scenario on SQL Server 2008R2:

• A usp to gather data and then a transfer data between two SQL Servers

This process is to be done with transaction at all levels of the process (usp, SSIS, and trigger)

enter image description here

In the data flow transferring the data to DB7.dbo.Dest, this table has an AFTER INSERT trigger which inserts the data that just came through into the final table DB7.dbo.FinalDestination:

CREATE TRIGGER [dbo].[Insert_OnStaging] ON [dbo].[Dest]
AFTER INSERT, UPDATE
AS
    BEGIN

SET NOCOUNT ON;    
SET XACT_ABORT ON;  --Rollsback complete transaction if there are any errors

BEGIN TRY

BEGIN TRANSACTION

INSERT INTO [DB7].[dbo].[FinalDestination] WITH (TABLOCK)
       (Column1
       ,Column2
       )
SELECT I.Column1, I.Column2 
FROM INSERTED I
INNER JOIN [DB7].[dbo].[Dest] PR
ON I.IDcol = PR.IDcol

COMMIT TRANSACTION

END TRY

BEGIN CATCH
IF @@TRANCOUNT > 0 AND XACT_STATE() <> 0
    ROLLBACK TRANSACTION;

DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorLine INT;

SELECT 
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorLine = ERROR_LINE()
;

RAISERROR (@ErrorMessage, -- Message text.
           @ErrorSeverity, -- Severity.
           @ErrorState, -- State.
           @ErrorLine  --Error Line
           );    
END CATCH;
END

At every level, I have tried to be defensive about the data due to the sensitivity of the data properly and completely reaching the final table.

In regards to the SSIS, from what I've read and tested it seems to work fine.

My biggest concern is the trigger which I scripted above. From my reading and understanding, setting XACT_ABORT ON will roll back the transaction inside the TRY block if any errors (in other words, there is an uncommitable transaction). In this case I went ahead and still added the rollback transaction portion in the CATCH block as a piece of mind since it would never reach (from my understanding). At the same time, I added the WITH (TABLOCK) option in order to lock the table while performing the INSERT.

In the case of the trigger, is the TRY...CATCH even necessary with the XACT_ABORT being ON? Is the COMMIT TRANSACTION necessary inside the TRY block? As I have also seen it committed after the CATCH block based on the @@TRANCOUNT

BEGIN TRY
BEGIN TRANSACTION
[Tsql here]
END TRY
BEGIN CATCH
[Error Handling]
END CATCH
IF @@TRANCOUNT > 0
COMMIT TRANSACTION
END

Answers and critique are welcomed and thank you in advance. Please excuse any typos as I tried to generalize the names...

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Ramon Gonzalez
  • 241
  • 1
  • 4
  • 11
  • I wouldn't recommend to start and commit a transaction inside a trigger, because it is already part of the transaction that the insert belongs to. If you rolback the transaction, remember that you won't rollback just the inner transaction, but all of them to the outermost one. – Guillermo Gutiérrez Sep 04 '13 at 14:11

1 Answers1

3

You need TRY..CATCH even though you're using XACT_ABORT. XACT_ABORT aborts the tran but continues running the batch/procedure! This is very, very nasty behavior. It means that DML/DDL can still run after an error has occurred but outside of a transaction so that you can never roll it back.

SQL Server does not have any mechanism to avoid that except for TRY..CATCH. I'm not sure what XACT_ABORT is ever good for. In your example neither does it help not does it hurt.

And yes, you can move the COMIT outside the TRY if you want to. Just make sure to properly balance it with the BEGIN TRAN.

usr
  • 168,620
  • 35
  • 240
  • 369
  • Based on what you said, if other DML/DDL exists outside of the transaction exists it would run those while being unable to roll back but if the only DDL/DML statements are within that same transaction, it should be fine and rollback everything? – Ramon Gonzalez Apr 24 '13 at 15:12
  • 1
    Yeah, jsut make sure everything is in the transaction and you're fine. SQL Server supports transacted DDL perfectly. Just wanted to make you aware of that issue. It is unpredictable to me which errors do abort a transaction and which don't. For that reason your try-catch approach is best-practice. – usr Apr 24 '13 at 15:18