SQL Server触发器循环

Roc*_*och 8 sql-server triggers sql-server-2000 infinite-loop

我想知道无论如何我都可以在两个表上添加触发器,将数据复制到另一个表.

例如:

  • 我有一个两个用户表,users_V1和users_V2,当用一个V1应用程序更新用户时,它会激活一个触发器,在users_V2中更新它.

  • 如果我想在V2表上添加相同的触发器以便在V2中更新用户时更新V1中的数据,它是否会进入无限循环?有没有办法避免这种情况.

Aar*_*ght 8

我不建议在处理过程中明确禁用触发器 - 这可能会导致奇怪的副作用.

检测(和防止)触发器中循环的最可靠方法是使用CONTEXT_INFO().

例:

CREATE TRIGGER tr_Table1_Update
ON Table1
FOR UPDATE AS

DECLARE @ctx VARBINARY(128) 
SELECT @ctx = CONTEXT_INFO() 
IF @ctx = 0xFF
    RETURN

SET @ctx = 0xFF

-- Trigger logic goes here
Run Code Online (Sandbox Code Playgroud)

有关更详细的示例,请参阅此链接.


CONTEXT_INFO()SQL Server 2000中的注意事项:

支持上下文信息,但显然CONTEXT_INFO功能不支持.你必须改用它:

SELECT @ctx = context_info
FROM master.dbo.sysprocesses
WHERE spid = @@SPID
Run Code Online (Sandbox Code Playgroud)


dev*_*vio 6

  • 使用TRIGGER_NESTLEVEL()来限制触发器递归,或者

  • 检查目标表是否需要UPDATE:

    IF (SELECT COUNT(1) 
    FROM users_V1 
    INNER JOIN inserted ON users_V1.ID = inserted.ID
    WHERE users_V1.field1 <> inserted.field1
    OR users_V1.field2 <> inserted.field2) > 0 BEGIN
    
    UPDATE users_V1 SET ...
    
    Run Code Online (Sandbox Code Playgroud)


小智 5

我有同样的问题。我尝试使用 CONTEXT_INFO() 但这是一个会话变量,所以它只在第一次工作!然后下次在会话期间触发触发器时,这将不起作用。所以我最终使用了一个变量,该变量在每个受影响的触发器中返回 Nest Level 以退出。

例子:

CREATE TRIGGER tr_Table1_Update
ON Table1
FOR UPDATE AS
BEGIN
      --Prevents Second Nested Call
      IF @@NESTLEVEL>1 RETURN 

      --Trigger logic goes here
END
Run Code Online (Sandbox Code Playgroud)

注意:或者如果要停止所有嵌套调用,请使用@@NESTLEVEL>0

另一个注意事项——本文中关于嵌套调用和递归调用似乎有很多混淆。最初的海报指的是嵌套触发器,其中一个触发器会导致另一个触发器触发,这将导致第一个触发器再次触发,依此类推。这是嵌套的,但根据 SQL Server,不是递归的,因为触发器没有直接调用/触发自身。递归不是“一个触发器[正在]调用另一个”。这是嵌套的,但不一定是递归的。您可以通过使用此处提到的一些设置启用/禁用递归和嵌套来测试这一点:关于嵌套的博客文章