SQL错误处理帮助:使用try catch的tran循环时

时间:2019-06-18 17:01:41

标签: sql-server tsql transactions try-catch

很抱歉,标题太恐怖了……一口气解释我要问的内容并不容易。

我想在一个循环中运行两个相关的DML查询...如果其中一个查询失败/引发错误...我想回滚该事务,退出循环并在引发错误时终止整个proc (因此作业将检测到故障)。我认为我所拥有的是正确的...但是我有几个问题,因为我想更好地了解它的工作原理。我已经阅读了Microsoft文档...但是在某些方面仍不清楚。

我知道使用SET XACT_ABORT ON;它将处理tran的回滚。这是否意味着我不需要检查IF (@@TRANCOUNT > 0)块中的CATCH

另一个问题...我有TRY...CATCH块的原因是由于WHILE循环...我不确定失败的事务是否还会终止proc,所以我用THROW强迫它吗?

这就是我所拥有的:(忽略它是一个无限循环的事实,我没有包括中断逻辑来使示例保持简单)

SET XACT_ABORT ON;
WHILE(1=1)
BEGIN
    BEGIN TRY
        BEGIN TRAN;
            --DML Query 1
            --DML Query 2
        COMMIT TRAN;
    END TRY
    BEGIN CATCH
        IF (@@TRANCOUNT > 0)
            ROLLBACK TRAN;

        THROW;
    END CATCH
END

更新

好的,我想自己弄清楚如何测试它,我很难弄清楚如何测试它,但是我想我现在已经掌握了。所以现在我很难发布问题:D

这是到目前为止我进行的测试...我将对其进行更改时对其进行更新。似乎IF (@@TRANCOUNT > 0)块中的CATCH并不是必需的,因为当我删除ROLLBACK并在失败后检查事务时,没有开放的事务。但是,如果我将其留在...中,IF语句将解析为true,并且仍然运行回滚而不会出错。

SET NOCOUNT ON;

IF OBJECT_ID('dbo.ChadTestTable1') IS NOT NULL DROP TABLE dbo.ChadTestTable1; --SELECT * FROM dbo.ChadTestTable1
CREATE TABLE dbo.ChadTestTable1 (TestField VARCHAR(10) NOT NULL)

IF OBJECT_ID('dbo.ChadTestTable2') IS NOT NULL DROP TABLE dbo.ChadTestTable2; --SELECT * FROM dbo.ChadTestTable2
CREATE TABLE dbo.ChadTestTable2 (TestField VARCHAR(10) NOT NULL)

INSERT INTO dbo.ChadTestTable1 (TestField) VALUES ('Test1')
INSERT INTO dbo.ChadTestTable2 (TestField) VALUES ('Test1')

SET XACT_ABORT ON;
WHILE(1=1)
BEGIN
    BEGIN TRY
        BEGIN TRAN;
            RAISERROR('Update first table',0,1) WITH NOWAIT;
            UPDATE dbo.ChadTestTable1 SET TestField = 'Test3'

            RAISERROR('Update second table',0,1) WITH NOWAIT;
            UPDATE dbo.ChadTestTable2 SET TestField = NULL

            RAISERROR('Updates done',0,1) WITH NOWAIT;
        COMMIT TRAN;
    END TRY
    BEGIN CATCH
        --It appears this isn't necessary...but if it's here, it still resolves to true and runs?
        IF (@@TRANCOUNT > 0)
        BEGIN
            RAISERROR('Rolling back transaction',0,1) WITH NOWAIT;
            ROLLBACK TRAN;
        END

        RAISERROR('Throwing Error',0,1) WITH NOWAIT;
        THROW;
    END CATCH

    RAISERROR('End of loop',0,1) WITH NOWAIT;
    BREAK;
END

SELECT * FROM dbo.ChadTestTable1 ctt
SELECT * FROM dbo.ChadTestTable2 ctt

1 个答案:

答案 0 :(得分:0)

所以我想出了自己的答案。我度过了一段相当艰难的时期,试图弄清楚如何自己进行测试,这就是为什么我提出了这个问题,但最终还是想出了办法。这就是我所发现的...您可能在Microsoft文档中可以找到90%的内容,但是我读到它后仍然感到困惑,所以我进行了蛮力测试。

这是我在阅读文档后发现的失踪之处:

  • XACT_ABORT ON-它不仅回滚事务,而且还会引发终止错误... aka,如果它正在进行并且事务处于循环中,并且在tran中引发错误,它将回滚tran,中断循环,并且将结束proc,并且在运行之后将不执行任何操作。 proc /脚本到此结束。

因此...我不需要TRY...CATCH块来运行THROW,并且我不需要回滚,因为它将自动完成。我很高兴发现这一点,因为这大大简化了我的代码。