XACT_ABORT 关闭时默认回滚事务
Transactions Rolling Back by default when XACT_ABORT is off
我有以下交易
BEGIN TRAN
DECLARE @TransactionAmount MONEY = 5.00
UPDATE Account SET Balance -= @TransactionAmount WHERE AccountID = 1
UPDATE Account SET Balance += @TransactionAmount WHERE AccountID = 'blah'
COMMIT TRAN
由于第二个 UPDATE
语句失败(AccountID
是一个 int
列)并且整个语句包含在 TRAN
块中,第一个语句中的更改回滚并且不会扣除 AccountID 1 的余额。
由于上面的代码中没有 ROLLBACK
语句,似乎 SQL 服务器自动回滚而不需要显式的 ROLLBACK
语句
当我查看它时,自动回滚行为似乎是由一个名为 xact_abort
的设置控制的。
我在网上找到了以下脚本,它打印出打开的设置
DECLARE @options INT
SELECT @options = @@OPTIONS
PRINT @options
IF ( (1 & @options) = 1 ) PRINT 'DISABLE_DEF_CNST_CHK'
IF ( (2 & @options) = 2 ) PRINT 'IMPLICIT_TRANSACTIONS'
IF ( (4 & @options) = 4 ) PRINT 'CURSOR_CLOSE_ON_COMMIT'
IF ( (8 & @options) = 8 ) PRINT 'ANSI_WARNINGS'
IF ( (16 & @options) = 16 ) PRINT 'ANSI_PADDING'
IF ( (32 & @options) = 32 ) PRINT 'ANSI_NULLS'
IF ( (64 & @options) = 64 ) PRINT 'ARITHABORT'
IF ( (128 & @options) = 128 ) PRINT 'ARITHIGNORE'
IF ( (256 & @options) = 256 ) PRINT 'QUOTED_IDENTIFIER'
IF ( (512 & @options) = 512 ) PRINT 'NOCOUNT'
IF ( (1024 & @options) = 1024 ) PRINT 'ANSI_NULL_DFLT_ON'
IF ( (2048 & @options) = 2048 ) PRINT 'ANSI_NULL_DFLT_OFF'
IF ( (4096 & @options) = 4096 ) PRINT 'CONCAT_NULL_YIELDS_NULL'
IF ( (8192 & @options) = 8192 ) PRINT 'NUMERIC_ROUNDABORT'
IF ( (16384 & @options) = 16384 ) PRINT 'XACT_ABORT'
但是,当 运行 在我的服务器上时,XACT_ABORT
没有出现在打印列表中,因此没有打开。
我的问题是:当 SQL 服务器似乎自动执行回滚时,为什么需要 ROLLBACK
语句?
如果XACT_ABORT = OFF
那么事务回滚与否就很难预测了。 SQL 服务器有时不会,有时会,有时甚至会中止批处理。 (是的,这没有任何意义。)其他可能的结果包括交易失败或切断连接。
在您的情况下,您可以可靠地使用 TRY-CATCH
来防止回滚并处理异常。
我发现尽可能不依赖错误处理是一个好习惯。相反,回滚事务。如果可能,还将错误处理推送到客户端。
如果您正在使用事务,建议在您的存储过程开始时设置 XACT_ABORT = ON。 Erland Sommarskog 有一篇关于错误处理的优秀文章:
我有以下交易
BEGIN TRAN
DECLARE @TransactionAmount MONEY = 5.00
UPDATE Account SET Balance -= @TransactionAmount WHERE AccountID = 1
UPDATE Account SET Balance += @TransactionAmount WHERE AccountID = 'blah'
COMMIT TRAN
由于第二个 UPDATE
语句失败(AccountID
是一个 int
列)并且整个语句包含在 TRAN
块中,第一个语句中的更改回滚并且不会扣除 AccountID 1 的余额。
由于上面的代码中没有 ROLLBACK
语句,似乎 SQL 服务器自动回滚而不需要显式的 ROLLBACK
语句
当我查看它时,自动回滚行为似乎是由一个名为 xact_abort
的设置控制的。
我在网上找到了以下脚本,它打印出打开的设置
DECLARE @options INT
SELECT @options = @@OPTIONS
PRINT @options
IF ( (1 & @options) = 1 ) PRINT 'DISABLE_DEF_CNST_CHK'
IF ( (2 & @options) = 2 ) PRINT 'IMPLICIT_TRANSACTIONS'
IF ( (4 & @options) = 4 ) PRINT 'CURSOR_CLOSE_ON_COMMIT'
IF ( (8 & @options) = 8 ) PRINT 'ANSI_WARNINGS'
IF ( (16 & @options) = 16 ) PRINT 'ANSI_PADDING'
IF ( (32 & @options) = 32 ) PRINT 'ANSI_NULLS'
IF ( (64 & @options) = 64 ) PRINT 'ARITHABORT'
IF ( (128 & @options) = 128 ) PRINT 'ARITHIGNORE'
IF ( (256 & @options) = 256 ) PRINT 'QUOTED_IDENTIFIER'
IF ( (512 & @options) = 512 ) PRINT 'NOCOUNT'
IF ( (1024 & @options) = 1024 ) PRINT 'ANSI_NULL_DFLT_ON'
IF ( (2048 & @options) = 2048 ) PRINT 'ANSI_NULL_DFLT_OFF'
IF ( (4096 & @options) = 4096 ) PRINT 'CONCAT_NULL_YIELDS_NULL'
IF ( (8192 & @options) = 8192 ) PRINT 'NUMERIC_ROUNDABORT'
IF ( (16384 & @options) = 16384 ) PRINT 'XACT_ABORT'
但是,当 运行 在我的服务器上时,XACT_ABORT
没有出现在打印列表中,因此没有打开。
我的问题是:当 SQL 服务器似乎自动执行回滚时,为什么需要 ROLLBACK
语句?
如果XACT_ABORT = OFF
那么事务回滚与否就很难预测了。 SQL 服务器有时不会,有时会,有时甚至会中止批处理。 (是的,这没有任何意义。)其他可能的结果包括交易失败或切断连接。
在您的情况下,您可以可靠地使用 TRY-CATCH
来防止回滚并处理异常。
我发现尽可能不依赖错误处理是一个好习惯。相反,回滚事务。如果可能,还将错误处理推送到客户端。
如果您正在使用事务,建议在您的存储过程开始时设置 XACT_ABORT = ON。 Erland Sommarskog 有一篇关于错误处理的优秀文章: