设置 xact_abort 并尝试一起捕捉
Posted
技术标签:
【中文标题】设置 xact_abort 并尝试一起捕捉【英文标题】:set xact_abort on and try catch together 【发布时间】:2013-04-05 16:59:09 【问题描述】:我的 sp 中有一个 try catch 块,在 try 中只有一个 insert 语句。如果是 pk 违规,则 catch 检查错误代码,如果是则进行更新。但有时我会得到“当前事务无法提交,并且无法支持写入日志文件的操作。回滚事务。
在批处理结束时检测到不可提交的事务。事务已回滚。”所以我添加了 xact_abort,但随后我不断收到“EXECUTE 后的事务计数表明 BEGIN 和 COMMIT 语句的数量不匹配。”我找到了这个。 http://www.ashishsheth.com/post/2009/08/14/Set-XACT_ABORT-ON-and-TryCatch-block-in-Sql-Server-2005.aspx
如果这是真的。如果打开 xact_abort 的 try 块中出现错误,我的 catch 代码会不会运行?
【问题讨论】:
【参考方案1】:至少对于 SQL SERVER 2008,SET XACT_ABORT ON 不会导致跳过 CATCH 块的错误:
这是我尝试使用 Northwind 数据库的代码
SET XACT_ABORT OFF
BEGIN TRY
SELECT 1, @@TRANCOUNT
BEGIN TRAN
UPDATE [dbo].[Categories]
SET Description='BLAH'
WHERE [CategoryID]=2
SELECT 2, @@TRANCOUNT
SELECT 1/0 as whoops
COMMIT
SELECT 3, @@TRANCOUNT
END TRY
BEGIN CATCH
SELECT 'In Catch. Error occured', 4, @@TRANCOUNT
IF (XACT_STATE()) = 0
BEGIN
SELECT
N'There is no transaction'
END;
IF (XACT_STATE()) = -1
BEGIN
SELECT
N'The transaction is in an uncommittable state.' +
'Rolling back transaction.'
ROLLBACK TRANSACTION;
END;
-- Test whether the transaction is committable.
IF (XACT_STATE()) = 1
BEGIN
SELECT
N'The transaction is committable.' +
'Committing transaction.'
COMMIT TRANSACTION;
END;
END CATCH
这显然会在遇到 SELECT 1/0 语句时强制出错。在 SET XACT_ABORT OFF 的情况下,当到达 CATCH 块时,XACT_STATE() 函数返回的值为 1,从而导致运行提交事务的代码。当 SET XACT_ABORT 开启时,在 CATCH 块中返回的值为 -1,因此执行回滚事务的代码。
这是基于:
http://msdn.microsoft.com/en-us/library/ms175976.aspx
【讨论】:
对不起,我迟到了...我同意迈克尔的观点,如果您启用了 XACT_ABORT,则在回滚之前“正在”执行 catch 块。有趣的是,你在 catch 块中所做的任何事情都会被回滚,因此看起来你甚至没有执行其中的任何内容。如果您在 CATCH 块中放置一条 select 语句,即使会引发错误,您也会看到它在 SSMS 中吐出。 @Eli - 当 XACT_ABORT 设置为 ON 时,try catch 是否有任何用途?因为无论如何所有错误都会导致事务回滚。 @variable 这是个好问题,我没想到。【参考方案2】:让我补充一点,在那种特定情况下(尝试插入,如果 PK 违规然后捕获并更新),最好使用 IF EXISTS (select....) 来查看该行是否存在并将您的那里有 UPDATE 语句。将您的 INSERT 语句放在 ELSE 块中。干净多了。
【讨论】:
以上是关于设置 xact_abort 并尝试一起捕捉的主要内容,如果未能解决你的问题,请参考以下文章
在存储过程中写SET XACT_ABORT ON 有什么用,不写会发生什么问题