设置 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 和事务

在存储过程中写SET XACT_ABORT ON 有什么用,不写会发生什么问题

arcgis捕捉容差设置多少能完全重合

尝试将 Node.js (Express) 设置为与虚拟主机一起使用,并遇到意外错误

如何使 SET XACT_ABORT ON 回滚事务?

实施步骤/捕捉 UISlider