如何正确使用 SET XACT_ABORT ON

9

我们最近被空投到一个有很糟糕的代码的新ETL项目中。 我手头拿着一个有700行和各种更新的查询。

我想用 SET XACT_ABORT ON; 调试它,目标是如果只有一个事务失败,就回滚所有内容。

但是我在 StackOverflow 上找到了几种实现方法,比如这个

BEGIN TRANSACTION;
BEGIN TRY

-- Multiple sql statements goes here

COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH

or this:

BEGIN TRY
BEGIN TRANSACTION

-- Multiple sql statements goes here

COMMIT TRANSACTION
END TRY
BEGIN CATCH
PRINT(ERROR_MESSAGE())
ROLLBACK TRANSACTION
END CATCH

而且这些用法都不使用SET XACT_ABORT ON;

我不明白,SET XACT_ABORT ON是否等同于使用BEGIN TRY BEGIN TRANSACTION

我能否只使用:

SET XACT_ABORT ON;

-- Multiple sql statements goes here

并除去所有以下内容:

BEGIN TRANSACTION;
BEGIN TRY

而且,我应该先使用 BEGIN TRANSACTION 还是 BEGIN TRY


说明:本文涉及 IT 技术相关内容。
3个回答

5

它们不同,它决定何时抛出错误。

应始终使用SET XACT_ABORT ON,因为它更一致; 几乎总是,一个错误会停止执行并抛出错误。否则,一半的事情会抛出错误,另一半会继续执行。

关于整个主题有一篇很好的文章Erland Sommarskog的网站上,并且如果您转到此处,您将看到一个描述此奇怪行为的表格。总之,我建议使用通用错误处理模式,因为它非常好地记录了文档,并为您提供了根据其文档进行调整的机会。


你是说将XACT_ABORT ON设置后,所有的错误都会进入CATCH块? - variable
不是全部,但更多。点击我的回答中的“此处”链接以查看完整列表。 - George Menoutis
当设置 SET XACT_ABORT 为 ON 时,TRY/CATCH 的作用是什么?从您分享的表格(来自该链接)可以看出,使用 TRY CATCH 时,对于可捕获列(CATCHABLE column),无论 XACT_ABORT 是 ON 还是 OFF 都没有影响。 - variable

3
如果您开启了XACT_ABORT ON,除非您需要记录错误日志,否则无需手动捕获任何错误。XACT_ABORT会导致所有错误使事务失败并回滚。
你只需要这样做:
SET XACT_ABORT ON;
BEGIN TRAN;
--do stuff
COMMIT;

如果只有一条语句,则不需要BEGIN TRAN;COMMIT;


我在@Charlieface进行了测试,如果我不使用BEGIN TRAN;COMMIT;,则表将在我的数据库中创建并插入数据。这意味着SET XACT_ABORT ON;需要BEGIN TRAN;COMMIT; - Francesco Mantovani
你误解了:如果你想要两个语句之间的原子性,那么需要使用 BEGIN TRAN COMMITXACT_ABORT ON 的意思是在出现错误时自动中止已打开的事务。所以 如果 你使用事务,那么应该使用 XACT_ABORT。但是单个语句不需要事务,因为它本身就有一个。 - Charlieface

2
感谢 @George Menoutis 提供的资源。
我在此发布我的实用解决方案:
SET XACT_ABORT ON;
BEGIN TRY
      BEGIN TRANSACTION;


      -- Multiple sql statements goes here


      COMMIT TRANSACTION;
END TRY
BEGIN CATCH
      IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
      THROW;
END CATCH;
GO

SET XACT_ABORT OFF;

谢谢@GeorgeMenoutis,请在您的回复中发布它。实际上,我遇到了与Erland代码相关的RETURN 55555问题。 - Francesco Mantovani
我猜只需要抛出@msg。 - George Menoutis
SET XACT_ABORT ON;会导致所有的错误都进入catch块吗? - variable
  1. 既然你已经设置了 SET XACT_ABORT ON;,为什么还要使用 try/catch?try catch有什么作用?
- variable
@variable,我不确定...但是我在每个示例中都看到它。我不知道SET XACT_ABORT ON;是否可以替换BEGIN TRY。我认为你必须同时使用两者。 - Francesco Mantovani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接