Справка по обработке ошибок SQL: цикл while с tran с try catch - PullRequest
1 голос
/ 18 июня 2019

Извините за ужасный заголовок ... не очень легко объяснить, что я спрашиваю в одной строке.

Я хочу запустить два зависимых DML-запроса в цикле ... если один иззапросы терпят неудачу / выдают ошибку ... Я хочу откатить транзакцию, выйти из цикла и завершить весь процесс при выдаче ошибки (чтобы задания могли обнаружить сбой).Я думаю, что у меня правильно, но у меня есть несколько вопросов, потому что я хочу лучше понять, как это работает.Я прочитал документацию Microsoft ... но мне все еще неясно по некоторым вещам.

Я знаю, используя SET XACT_ABORT ON;, что он будет обрабатывать откат для trans.Означает ли это, что мне не нужно проверять IF (@@TRANCOUNT > 0) в блоке CATCH?

Другой вопрос ... причина, по которой у меня есть блок TRY...CATCH, заключается в цикле WHILE...Я не уверен, что неудачная транзакция также прервет процесс, поэтому я заставляю его с помощью 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 голосов
/ 18 июня 2019

Так что я понял свой ответ. У меня были довольно трудные времена, когда я пытался понять, как это проверить сам, поэтому я написал вопрос, но в конце концов понял. Вот что я нашел ... 90% из них вы, вероятно, можете найти в документации Microsoft, но я прочитал это, и все еще оставался в замешательстве, поэтому я привел к брутфорс-тестированию.

Вот что я обнаружил, что мне не хватало после прочтения документации:

  • XACT_ABORT ON - Он не только выполняет откат транзакции, но также выдает завершающую ошибку ... иначе, если она включена, и транзакция находится в цикле, и в трансе выдается ошибка, она будет откатите trans, прервите цикл, и он также завершит процесс и ничего после него не запустится. На этом процесс / скрипт заканчивается.

Поэтому ... мне не нужен блок TRY...CATCH для запуска THROW, и мне не нужно откатываться, потому что это будет сделано автоматически. Я счастлив, что нашел это, потому что это немного упрощает мой код.

...