Игнорирование ошибок в триггере - PullRequest
6 голосов
/ 02 апреля 2012

У меня есть хранимая процедура, которая вызывается внутри триггера при вставке / обновлении / удалении.

Проблема в том, что внутри этого SP есть определенный блок кода, который не является критичным. Поэтому я хочу игнорировать любые ошибки, возникающие из этого блока кода.

Я вставил этот блок кода в блок TRY CATCH. Но, к моему удивлению, я получил следующую ошибку:

Текущая транзакция не может быть зафиксирована и не может поддерживать операции, которые записывают в файл журнала. Откат транзакции.

Затем я попытался использовать SAVE & ROLLBACK TRANSACTION вместе с TRY CATCH, что тоже привело к ошибке:

Текущая транзакция не может быть зафиксирована и не может быть отменена до точки сохранения. Откат всей транзакции.

Версия моего сервера: Microsoft SQL Server 2008 (SP2) - 10.0.4279.0 (X64)

Образец DDL:

IF OBJECT_ID('TestTrigger') IS NOT NULL
    DROP TRIGGER TestTrigger
GO
IF OBJECT_ID('TestProcedure') IS NOT NULL
    DROP PROCEDURE TestProcedure
GO
IF OBJECT_ID('TestTable') IS NOT NULL
    DROP TABLE TestTable
GO

CREATE TABLE TestTable (Data VARCHAR(20))
GO

CREATE PROC TestProcedure       
AS      
BEGIN 

    SAVE TRANSACTION Fallback
    BEGIN TRY
        DECLARE @a INT = 1/0
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION Fallback
    END CATCH
END
GO

CREATE TRIGGER TestTrigger
ON TestTable
FOR INSERT, UPDATE, DELETE 
AS
BEGIN
    EXEC TestProcedure   
END
GO

Код для репликации ошибки:

BEGIN TRANSACTION
INSERT INTO TestTable VALUES('data')
IF @@ERROR > 0
    ROLLBACK TRANSACTION
ELSE
    COMMIT TRANSACTION
GO

Ответы [ 4 ]

12 голосов
/ 27 ноября 2012

Я переживал те же мучения, и я просто решил это !!!Просто добавьте эту единственную строку на самом первом шаге вашего TRIGGER, и все будет в порядке:

SET XACT_ABORT OFF;

В моем случае я обрабатываю ошибку при загрузке определенной таблицы пакетом, который вызвалошибка и переменные ошибки из SQL.

Значение по умолчанию для XACT_ABORT равно ON , поэтому вся транзакция не будет зафиксирована, даже если вы обрабатываете ошибку внутри блока TRY CATCH (так же, какЯ делаю).Установка его значения для OFF приведет к фиксации транзакции даже при возникновении ошибки.

Однако я не проверял его, когда ошибка не обрабатывается ...

Для получения дополнительной информации:

1 голос
/ 02 апреля 2012

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

Например, ваш триггер становится:

CREATE TRIGGER TestTrigger
ON TestTable
FOR INSERT, UPDATE, DELETE 
AS
BEGIN
    INSERT INTO QueueTable (Col1,Col2)
    SELECT COALESCE(i.Col1,d.Col1),COALESCE(i.Col2,d.Col2) from inserted i,deleted d
END
GO

Вы не должны делать внутри триггера что-либо, что можетпотерпите неудачу, если только вы do не захотите принудительно завершить транзакцию, которая инициировала действие триггера.

0 голосов
/ 02 апреля 2012

Не думаю, что вы можете использовать точки сохранения внутри триггера. Я имею в виду, вы можете, но я гуглил об этом, и я увидел несколько человек, которые говорили, что они не работают. Если вы заменяете «сохранить транзакцию» на начальную транзакцию, она компилируется. Конечно, в этом нет необходимости, поскольку у вас есть внешний элемент управления транзакциями, а внутренний откат будет выполнять откат всего.

0 голосов
/ 02 апреля 2012
...