如何防止数据库触发器从递归?(How do I prevent a database trigger

2019-07-21 05:27发布

我已经有了一个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

谁能告诉我怎么可以防止触发的插入再次开球另一个触发?

Answer 1:

不知道这是有关业务方案的问题了,但如果你来到这里,了解如何防止递归或相互递归从一个触发事件,你可以测试这个像这样:

IF TRIGGER_NESTLEVEL() <= 1/*this update is not coming from some other trigger*/

MSDN 链接



Answer 2:

我看到三种可能性:

  1. 禁用触发器递归

    这将防止烧调用另一个触发或再次调用自身的触发器。 要做到这一点,执行以下命令:

     ALTER DATABASE MyDataBase SET RECURSIVE_TRIGGERS OFF GO 
  2. 使用INSTEAD OF UPDATE,INSERT触发器

    使用INSTEAD OF触发器可以控制任何一列正在更新/插入,并调用命令之前甚至取代。

  3. 通过使用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 


Answer 3:

ALTER DATABASE <dbname> SET RECURSIVE_TRIGGERS OFF

RECURSIVE_TRIGGERS {ON | OFF } OFF}

触发器的递归激发是允许的。

后直接只递归激发触发器是不允许的。 也禁用AFTER触发器的间接递归,通过使用sp_configure将nested triggers服务器选项设置为0。

当RECURSIVE_TRIGGERS设置为OFF时,仅防止直接递归。 要禁用间接递归,还必须将嵌套触发器服务器选项设置为0。

此选项的状态可通过检查在sys.databases目录视图中is_recursive_triggers_on列或DATABASEPROPERTYEX函数的IsRecursiveTriggersEnabled属性来确定。



Answer 4:

我想我知道了:)

当标题是越来越“更新”(读:插入或更新),然后更新的唯一主题。 当触发被跑第二次,uniquesubject场得到更新,所以它停下来,离开触发器。

此外,我将它搞定得到改变多行 - >我总是忘了这个用触发器。

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


Answer 5:

TRIGGER_NESTLEVEL可用于防止特定的触发的递归,但到触发器的对象标识传递到功能是重要的。 否则,你也将防止触发器射击时的插入或更新由其他触发器进行:

   IF TRIGGER_NESTLEVEL(OBJECT_ID('dbo.mytrigger')) > 1
         BEGIN
             PRINT 'mytrigger exiting because TRIGGER_NESTLEVEL > 1 ';
             RETURN;
     END;

从MSDN :

当没有指定参数,TRIGGER_NESTLEVEL返回调用堆栈上触发器的总数。 这包括本身。

参考: 避免递归触发器



Answer 6:

你可以有一个独立的NULLABLE列指示UniqueTitle是否成立。

其设置为true值触发,并有触发什么也不做,如果它的值是“插在”真



Answer 7:

为了完整起见,我将添加一些东西。 如果你有一个特定的触发之后,你只需要运行一次,你可以将它设置为运行使用sp_settriggerorder最后。

我也会考虑,如果它可能不是最好的,以正在做递归到一个触发的触发相结合。



文章来源: How do I prevent a database trigger from recursing?