防止触发器的相互递归执行?

Posted

技术标签:

【中文标题】防止触发器的相互递归执行?【英文标题】:Prevent mutually recursive execution of triggers? 【发布时间】:2010-09-30 15:47:21 【问题描述】:

假设您有表PresentationsEvents。保存演示文稿并包含基本事件信息(例如位置和日期)时,将使用触发器自动创建事件。 (恐怕由于技术原因,不可能简单地将数据保存在一个地方并使用视图。)此外,稍后在演示文稿中更改此信息时,触发器也会将更新复制到事件中,像这样:

CREATE TRIGGER update_presentations
ON Presentations
AFTER UPDATE
AS
BEGIN
    UPDATE Events
    SET Events.Date = Presentations.Date,
        Events.Location = Presentations.Location
    FROM Presentations INNER JOIN Events ON Presentations.EventID = Events.ID
    WHERE Presentations.ID IN (SELECT ID FROM inserted)
END

现在,客户希望这样,如果用户更改了 事件 中的信息,它也应该返回到演示文稿。由于显而易见的原因,我不能反过来:

CREATE TRIGGER update_events
ON Events
AFTER UPDATE
AS
BEGIN
    UPDATE Presentations
    SET Presentations.Date = Events.Date,
        Presentations.Location = Events.Location
    FROM Events INNER JOIN Presentations ON Events.PresentationID = Presentations.ID
    WHERE Events.ID IN (SELECT ID FROM inserted)
END

毕竟,这会导致每个触发器一个接一个地触发。我可以做的是在两个表中添加一个列last_edit_by,其中包含一个用户ID。如果触发器使用特殊的无效 ID 填充(例如,通过使实际人员的所有用户 ID 为正,但脚本的用户 ID 为负),我可以将其用作退出条件:

    AND last_edit_by >= 0

这可能有效,但我想做的是向 SQL 服务器表明,在事务中,触发器应该只触发一次。有没有办法检查这个?或者检查一个表是否已经受到触发器的影响?


回答感谢史蒂夫·罗宾斯:

只需将可能嵌套的 UPDATE 语句包装在一个 IF 条件检查 trigger_nestlevel() 中。例如:

CREATE TRIGGER update_presentations
ON Presentations
AFTER UPDATE
AS
BEGIN
    IF trigger_nestlevel() < 2
        UPDATE Events
        SET Events.Date = Presentations.Date,
            Events.Location = Presentations.Location
        FROM Presentations INNER JOIN Events ON Presentations.EventID = Events.ID
        WHERE Presentations.ID IN (SELECT ID FROM inserted)
END

请注意,trigger_nestlevel() 似乎是从 1 开始的,而不是从 0 开始的。如果您希望这两个触发器中的每一个都执行一次,但不是更频繁,只需检查两个触发器中的 trigger_nestlevel() &lt; 3

【问题讨论】:

【参考方案1】:

我不确定是否为每个事务执行此操作,但您是否需要为其他部分打开嵌套触发器?如果您在服务器上关闭它们,则触发器不会从另一个触发器更新表时触发。

编辑(来自 cmets 的回答):您需要更改触发器 A 以使用 TRIGGER_NESTLEVEL

【讨论】:

嵌套触发器实际上在该数据库上被禁用。我的问题是触发器 A 触发 B 触发 A,而不是 A 直接触发 A。该设置不会阻止这一点。 那是递归触发器,我现在不在一台机器上,但我确信也有嵌套触发器,您可以使用 sp_config 进行配置。自从我遇到这个问题以来已经有几年了。 你是对的;嵌套触发器是另一种选择。但是按照我阅读它的文档的方式,它会阻止 B 在 A 之后触发,而我想阻止 A 第二次触发。 啊,对不起,我看错了你的帖子。您需要更改触发器 A 以使用 TRIGGER_NESTLEVEL (msdn.microsoft.com/en-us/library/ms182737.aspx) 并且在嵌套时不运行。 这听起来正是我想要的! :)

以上是关于防止触发器的相互递归执行?的主要内容,如果未能解决你的问题,请参考以下文章

sql触发器 递归 问题

javascript 如何防止多次触发hover事件

如何防止ajax调用两次触发

防止 QMenu 在其 QAction 之一未触发时关闭

如何防止意外触摸触发 swift 4.2 中的 touchesBegan?

Trigger 触发器