在存储过程中使用“SET XACT_ABORT ON”有什么好处?

在存储过程中使用SET XACT_ABORT ON有什么好处?

SET XACT_ABORT ON指示SQL Server回滚整个事务,并在发生运行时错误时中止批处理。 它涵盖了在客户端应用程序中发生命令超时的情况,而不是在SQL Server本身中(不包括在默认的XACT_ABORT OFF设置中)。

由于查询超时将导致事务处于打开状态,因此在所有具有显式事务的存储过程中build议使用SET XACT_ABORT ON (除非您有特殊的理由不这样做),因为应用程序对打开事务的连接执行工作的后果是灾难性的。

关于Dan Guzman的博客有一个非常好的概述,

在我看来,SET XACT_ABORT ON被SQL 2k5中的BEGIN TRY / BEGIN CATCH添加了。 在Transact-SQL中的exception块之前,处理错误和不平衡的过程非常难以实现(与入口相比,在退出时具有不同的@@ TRANCOUNT)。

随着Transact-SQL的增加,exception处理更容易编写正确的程序,保证正确地平衡事务。 例如我使用这个模板进行exception处理和嵌套事务 :

 create procedure [usp_my_procedure_name] as begin set nocount on; declare @trancount int; set @trancount = @@trancount; begin try if @trancount = 0 begin transaction else save transaction usp_my_procedure_name; -- Do the actual work here lbexit: if @trancount = 0 commit; end try begin catch declare @error int, @message varchar(4000), @xstate int; select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE(); if @xstate = -1 rollback; if @xstate = 1 and @trancount = 0 rollback if @xstate = 1 and @trancount > 0 rollback transaction usp_my_procedure_name; raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ; end catch end go 

它允许我编写primefaces程序,以便在可恢复错误的情况下只回滚自己的工作。

Transact-SQL程序面临的主要问题之一是数据纯度 :有时收到的参数或表中的数据是错误的,导致重复的关键错误,参照约束错误,检查约束错误等等。 毕竟,这正是这些约束的作用,如果这些数据纯度错误是不可能的,并且都被业务逻辑所捕获,那么这些约束将会全部过时(夸大的夸大效果)。 如果XACT_ABORT为ON,则所有这些错误都会导致整个事务丢失,而不是能够优雅地编写处理exception的exception块。 一个典型的例子是试图做一个INSERT并恢复到违反PK的UPDATE。

引用MSDN :

当SET XACT_ABORT为ON时,如果Transact-SQL语句引发运行时错误,则整个事务将终止并回滚。 当SET XACT_ABORT为OFF时,在某些情况下,只有导致错误的Transact-SQL语句被回滚,事务继续处理。

实际上,这意味着某些陈述可能失败,交易“部分完成”,并且呼叫者可能没有这种失败的迹象。

一个简单的例子:

 INSERT INTO t1 VALUES (1/0) INSERT INTO t2 VALUES (1/1) SELECT 'Everything is fine' 

这段代码会在XACT_ABORT OFF的情况下执行'successful',并且会以XACT_ABORT ON('INSERT INTO t2'不会被执行,并且客户端应用程序会引发一个exception)的错误结束。

作为一种更灵活的方法,您可以在每个语句(旧学校)之后检查@@ ERROR,或使用TRY … CATCH块(MSSQL2005 +)。 我个人更喜欢设置XACT_ABORT,只要没有任何理由进行一些高级的error handling。

关于客户端超时以及使用XACT_ABORT来处理它们,在我看来,至less有一个非常好的理由在SqlClient等客户端API中超时,这是为了防止客户端应用程序代码在SQL服务器代码中发生死锁。 在这种情况下,客户端代码没有任何错误,但是必须保护它免于阻止在服务器上等待命令完成。 所以相反,如果客户端超时必须存在以保护客户端代码,那么XACT_ABORT ON必须保护服务器代码免受客户端中止,以防服务器代码执行的时间比客户端愿意等待的时间长。

它用于事务pipe理,以确保任何错误导致事务被回滚。