【问题标题】:Transaction handling in Trigger (TRY/CATCH....XACT_ABORT ON)触发器中的事务处理(TRY/CATCH....XACT_ABORT ON)
【发布时间】:2013-04-23 15:37:35
【问题描述】:

我有SQL Server 2008R2上的流程场景:

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

这个过程是在所有进程级别(usp、SSIS 和触发器)的事务中完成的

在将数据传输到 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

欢迎回答和批评,并在此先感谢您。请原谅我试图概括名称时的任何拼写错误...

【问题讨论】:

  • 我不建议在触发器中启动和提交事务,因为它已经是插入所属事务的一部分。如果您回滚事务,请记住您不会只回滚内部事务,而是将它们全部回滚到最外层。

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


【解决方案1】:

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

除了TRY..CATCH,SQL Server 没有任何机制来避免这种情况。我不确定XACT_ABORT 有什么用处。在您的示例中,它也无济于事。

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

【讨论】:

  • 根据您所说的,如果在事务之外存在其他 DML/DDL 存在,它将在无法回滚的情况下运行那些,但如果唯一的 DDL/DML 语句在同一个事务中,它应该没问题并回滚所有内容?
  • 是的,只要确保一切都在交易中,你就没事了。 SQL Server 完美支持事务型 DDL。只是想让你意识到这个问题。我无法预测哪些错误会中止事务,哪些不会。因此,您的 try-catch 方法是最佳实践。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-27
  • 2015-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-19
  • 2011-04-01
相关资源
最近更新 更多