TSQL сделать триггер сбой молча - PullRequest
6 голосов
/ 29 января 2010

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

Пример ниже показывает, что я имею в виду. Триггер преднамеренно создает условие ошибки, в результате чего исходная вставка («1») никогда не вставляется в таблицу. Try / Catch, похоже, не сработал. Подобный старый вопрос о переполнении стека не дал ответа, за исключением "предотвратить возникновение ошибки в первую очередь" - что не всегда возможно / просто.

Есть еще идеи?

create table test 
(
  a int not null
);
go

create trigger testTrigger on test 
after insert as 
begin 
  insert into test select null;
end;
go

insert into test values ( 1 );

Ответы [ 3 ]

2 голосов
/ 29 января 2010

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

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

т.е.

INSERT INTO test WHERE val IS NOT NULL

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

т.е.

INSERT INTO ACTION_QUEUE (action, parameters) VALUES ('INSERT INTO TEST', val)
1 голос
/ 29 января 2010

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

Это то же самое, что и:

DROP TABLE test

CREATE TABLE test 
(
        a INT NOT NULL
)

GO

SET XACT_ABORT ON
GO

BEGIN TRANSACTION

BEGIN TRY
        INSERT
        INTO    test
        SELECT  NULL
END TRY
BEGIN CATCH
        INSERT
        INTO    test
        SELECT  1
END CATCH

, что приводит к обреченной транзакции, за исключением того, что невозможно отключить XACT_ABORT внутри триггера.

SQL Server также не хватает автономных транзакций.

Это еще одна причина, почему вы должны поместить всю свою логику в хранимые процедуры, а не в триггеры.

0 голосов
/ 01 мая 2012
  1. Вы можете отключить XACT_ABORT внутри триггера (будьте осторожны)
  2. Вы можете иметь триггер для вызова хранимой процедуры.(Сейчас я борюсь с противоположной проблемой: я хочу, чтобы транзакция была прервана, но поскольку логика находится в SP, вызываемом из триггера, а не в самом триггере, этого не происходит.)
...