【问题标题】:SQL Error Handling Help: While loop with tran with try catchSQL 错误处理帮助:带有 tran 和 try catch 的 While 循环
【发布时间】:2019-06-18 17:01:41
【问题描述】:

对不起这个可怕的标题......我在一行中要解释什么并不容易。

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

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

另一个问题...我有 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

这是我到目前为止所做的测试...我会在对其进行更改时对其进行更新。看来CATCH 块中的IF (@@TRANCOUNT > 0) 不是必需的,因为当我删除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

【问题讨论】:

    标签: sql-server tsql transactions try-catch


    【解决方案1】:

    所以我想出了自己的答案。我试图弄清楚如何自己测试这个问题相当困难,这就是我发布这个问题的原因,但我最终想通了。这是我发现的……90% 的内容您可能可以在 Microsoft 文档中找到,但我读到了,仍然感到困惑,所以我进行了暴力测试。

    以下是我在阅读文档后发现的缺失:

    • XACT_ABORT ON - 它不仅回滚事务,而且还会抛出终止错误……也就是说,如果它打开并且事务处于循环中,并且在 tran 中抛出错误,它将回滚 tran , 打破循环,它也将结束 proc 并且在它运行之后什么都没有。 proc/script 到此结束。

    因此...我不需要TRY...CATCH 块来运行THROW,我也不需要回滚,因为它会自动完成。我很高兴找到这个,因为这大大简化了我的代码。

    【讨论】:

      猜你喜欢
      • 2017-10-09
      • 1970-01-01
      • 2021-11-01
      • 2011-11-07
      • 1970-01-01
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多