Вопрос

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...

Это было полезно?

Решение

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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top