Включи xact_abort и попробуй поймать вместе
У меня есть блок try catch в моем sp с просто оператором вставки в try. код ошибки проверки улова, если это нарушение pk, если это так, то выполните обновление. но иногда я получаю "Текущая транзакция не может быть зафиксирована и не может поддерживать операции, которые записывают в файл журнала. Откат транзакции.
Нефиксированная транзакция обнаружена в конце пакета. Транзакция откатывается.", Поэтому я добавил 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
если это правда. мой код перехвата не запустится, если в моем блоке try будет ошибка с включенным xact_abort?
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, что приводит к запуску кода, выполняющего транзакцию COMMIT. Когда SET XACT_ABORT включен, возвращаемое значение в блоке CATCH равно -1, поэтому выполняется код, который ROLL возвращает обратно транзакции.
Это основано на:
Позвольте мне добавить, что в этом конкретном сценарии (попробуйте вставить, если нарушение PK затем поймать и обновить), было бы лучше использовать IF EXISTS (выберите....), чтобы увидеть, есть ли строка, и поместить туда свой оператор UPDATE., Поместите свой оператор INSERT в блок ELSE. Гораздо чище.