Как предотвратить рекурсирование триггера базы данных?
У меня есть следующий триггер в таблице для базы данных SQL Server 2008. Он рекурсирует, поэтому мне нужно остановить его.
После того, как я вставляю или обновляю запись, я пытаюсь просто обновить одно поле в этой таблице.
Здесь триггер:
ALTER TRIGGER [dbo].[tblMediaAfterInsertOrUpdate]
ON [dbo].[tblMedia]
BEFORE INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON
DECLARE @IdMedia INTEGER,
@NewSubject NVARCHAR(200)
SELECT @IdMedia = IdMedia, @NewSubject = Title
FROM INSERTED
-- Now update the unique subject field.
-- NOTE: dbo.CreateUniqueSubject is my own function.
-- It just does some string manipulation.
UPDATE tblMedia
SET UniqueTitle = dbo.CreateUniqueSubject(@NewSubject) +
CAST((IdMedia) AS VARCHAR(10))
WHERE tblMedia.IdMedia = @IdMedia
END
Может ли кто-нибудь сказать мне, как я могу предотвратить запуск триггерной вставки с другого триггера снова?
Ответы
Ответ 1
Не уверен, что это относится к вопросу OP больше, но если вы пришли сюда, чтобы узнать, как предотвратить рекурсию или взаимную рекурсию в триггере, вы можете проверить это так:
IF TRIGGER_NESTLEVEL() <= 1/*this update is not coming from some other trigger*/
MSDN ссылка
Ответ 2
Я вижу три возможности:
-
Отключить рекурсию триггера:
Это предотвратит запуск триггера для вызова другого триггера или повторного вызова. Для этого выполните следующую команду:
ALTER DATABASE MyDataBase SET RECURSIVE_TRIGGERS OFF
GO
-
Использовать триггер INSTEAD OF UPDATE, INSERT
Используя триггер INSTEAD OF
, вы можете контролировать любой обновляемый/вставленный столбец и даже заменять перед вызовом команды.
-
Управляйте триггером, предотвращая использование IF UPDATE
Тестирование столбца подскажет вам с разумной точностью, если вы вызываете сам вызов. Для этого используйте предложение IF UPDATE()
, подобное:
ALTER TRIGGER [dbo].[tblMediaAfterInsertOrUpdate]
ON [dbo].[tblMedia]
FOR INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON
DECLARE @IdMedia INTEGER,
@NewSubject NVARCHAR(200)
IF UPDATE(UniqueTitle)
RETURN;
-- What is the new subject being inserted?
SELECT @IdMedia = IdMedia, @NewSubject = Title
FROM INSERTED
-- Now update the unique subject field.
-- NOTE: dbo.CreateUniqueSubject is my own function.
-- It just does some string manipulation.
UPDATE tblMedia
SET UniqueTitle = dbo.CreateUniqueSubject(@NewSubject) +
CAST((IdMedia) AS VARCHAR(10))
WHERE tblMedia.IdMedia = @IdMedia
END
Ответ 3
ALTER DATABASE <dbname> SET RECURSIVE_TRIGGERS OFF
RECURSIVE_TRIGGERS {ON | OFF}
ВКЛ Разрешено рекурсивное срабатывание триггеров AFTER.
ВЫКЛ Разрешено только прямое рекурсивное включение триггеров AFTER. к также отключить косвенную рекурсию ПОСЛЕ триггеров установите вложенный параметр сервера триггеров равен 0, используя sp_configure.
Запрещается только прямая рекурсия, если для параметра RECURSIVE_TRIGGERS установлено значение OFF. Чтобы отключить косвенную рекурсию, вы также должны устанавливать вложенные триггеры сервер для 0.
Статус этого параметра можно определить, изучив is_recursive_triggers_on в столбце Просмотр каталога каталога sys.databases или IsRecursiveTriggersEnabled свойство функция DATABASEPROPERTYEX.
Ответ 4
Я думаю, что получил:)
Когда заголовок получает "обновление" (чтение: вставлено или обновлено), обновите уникальный объект. Когда триггер запускается во второй раз, поле uniquesubject обновляется, поэтому он останавливается и покидает триггер.
Кроме того, я заставил его обрабатывать MULTIPLE строки, которые меняются → Я всегда забываю об этом с помощью триггеров.
ALTER TRIGGER [dbo].[tblMediaAfterInsert]
ON [dbo].[tblMedia]
FOR INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON
-- If the Title is getting inserted OR updated then update the unique subject.
IF UPDATE(Title) BEGIN
-- Now update all the unique subject fields that have been inserted or updated.
UPDATE tblMedia
SET UniqueTitle = dbo.CreateUniqueSubject(b.Title) +
CAST((b.IdMedia) AS VARCHAR(10))
FROM tblMedia a
INNER JOIN INSERTED b on a.IdMedia = b.IdMedia
END
END
Ответ 5
У вас может быть отдельный столбец NULLABLE, указывающий, был ли установлен UniqueTitle.
Установите значение true в триггере, и триггер ничего не делает, если значение true в "INSERTED"
Ответ 6
TRIGGER_NESTLEVEL
может использоваться для предотвращения рекурсии определенного триггера, но важно передать идентификатор объекта триггера в функцию. В противном случае вы также предотвратите срабатывание триггера, когда вставка или обновление будут сделаны другим триггером:
IF TRIGGER_NESTLEVEL(OBJECT_ID('dbo.mytrigger')) > 1
BEGIN
PRINT 'mytrigger exiting because TRIGGER_NESTLEVEL > 1 ';
RETURN;
END;
От MSDN:
Если параметры не указаны, TRIGGER_NESTLEVEL возвращает общее количество количество триггеров в стеке вызовов. Это включает в себя.
Ссылка:
Избегать рекурсивных триггеров
Ответ 7
Для полноты я добавлю несколько вещей. Если у вас есть определенный после триггера, который вы хотите запустить только один раз, вы можете настроить его для последнего запуска, используя sp_settriggerorder.
Я бы также подумал, не лучше ли комбинировать триггеры, которые делают рекурсию в один триггер.