触发器中的事务处理(TRY / CATCH .... XACT_ABORT ON)

时间:2013-04-23 15:37:36

标签: sql triggers sql-server-2008-r2 sqltransaction xact-abort

我在SQL Server 2008R2上有进程方案:

•usp用于收集数据,然后在两个SQL Server之间传输数据

此过程将在流程的所有级别(usp,SSIS和触发器)中使用事务完成

enter image description here

在将数据传输到DB7.dbo.Dest的数据流中,此表有一个AFTER INSERT触发器,它将刚刚进入最终表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

在各个层面上,由于数据的敏感性和完全进入决赛桌,我试图对数据采取防御措施。

关于SSIS,从我阅读和测试的内容来看,似乎工作正常。

我最担心的是我在上面编写的触发器。根据我的阅读和理解,设置XACT_ABORT ON将在TRY块内回滚事务(如果有任何错误(换句话说,存在不可承受的事务))。在这种情况下,我继续前进,仍然在CATCH块中添加了回滚事务部分,因为它永远不会达到(根据我的理解)。同时,我添加了WITH(TABLOCK)选项,以便在执行INSERT时锁定表。

在触发器的情况下,即使XACT_ABORT为ON,是否还需要TRY ... CATCH?在TRY块内是否需要COMMIT TRANSACTION?正如我在基于@@ TRANCOUNT

的CATCH块之后看到的那样
BEGIN TRY
BEGIN TRANSACTION
[Tsql here]
END TRY
BEGIN CATCH
[Error Handling]
END CATCH
IF @@TRANCOUNT > 0
COMMIT TRANSACTION
END

欢迎回答和批评,并提前感谢您。请原谅任何错别字,因为我试图概括这些名字......

1 个答案:

答案 0 :(得分:2)

即使您使用TRY..CATCH,也需要XACT_ABORTXACT_ABORT中止tran但继续运行批处理/过程!这是非常非常讨厌的行为。这意味着DML / DDL仍然可以在发生错误后但在事务之外运行,以便您永远不会回滚。

除了TRY..CATCH之外,SQL Server没有任何机制可以避免这种情况。我不确定XACT_ABORT有什么好处。在你的例子中,它既没有帮助也没有伤害它。

是的,如果您愿意,可以将COMIT移到TRY之外。只需确保与BEGIN TRAN正确平衡。