2010-01-29 3 views
6

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

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

Любые другие идеи?

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); 
+1

Почему Try/Catch не работает? – cjk

+0

@ck: потому что нарушения ограничений внутри триггеров обрекают транзакции. – Quassnoi

ответ

2

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

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

т.е.

INSERT INTO test WHERE val IS NOT NULL 

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

т.е.

INSERT INTO ACTION_QUEUE (action, parameters) VALUES ('INSERT INTO TEST', val) 
+0

Боюсь, что это будет единственный способ. Это сложно. Пожалуйста, см. Мой комментарий к отвечу Кваснуи ниже. – BuschnicK

+0

@BuschnicK Создание триггеров - одна из наиболее инвазивных вещей, которые вы можете сделать в системе. Это часть схемы базы данных для обеспечения поведения базы данных, и вы делаете это в чужой базе данных. У них есть свое место, но я не думаю, что это использование подходит, если вы не можете гарантировать, что они ведут себя хорошо.Честно говоря, если вы используете триггер в качестве своего единственного механизма для отправки изменений, если триггер должен был терпеть неудачу, ваши изменения не будут отправлены, но транзакция может завершиться, и вы потеряете сообщение с данными об изменениях, как бы вы в любом случае, повторно синхронизируйте свои данные? –

+0

@BuschnicK Вам было бы лучше изучить какой-то захват данных изменений или другую технику ETL для сравнения изменений с момента последнего моментального снимка. –

1

Из-за способа Триггеры реализуются в 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

на самом деле вы не обречены на транзакции, если вы не используете try..catch. –

+0

@Alex: уверен, операция просто атомарно отменена. Это было просто, чтобы продемонстрировать, что происходит. – Quassnoi

+0

Как помогают хранимые процедуры? Я подумал, что если что-нибудь триггер вызовет хранимую процедуру ... Чтобы немного рассказать о том, что я пытаюсь архивировать здесь: у нас есть система ERP, поставляемая поставщиком, и вы хотите получать свежие данные из это таблицы. Мы прикрепляем триггеры к их столам, массируем данные и копируем их в нашу собственную базу данных. Мы хотим гарантировать, что наши триггеры никогда не сбой, потому что это может вызвать проблемы в исходной системе ERP. – BuschnicK

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