Извините за ужасный заголовок ... не очень легко объяснить, что я спрашиваю в одной строке.
Я хочу запустить два зависимых 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