SQL 2005中的递归更新触发器问题

Atu*_*tul 1 t-sql recursion triggers sql-server-2005

下面是带有注释的代码片段,用于描述问题陈述.我们有一个更新触发器,在内部调用同一个表上的另一个更新触发器,尽管Recursive Trigger Enabled Property Set为false.

想了解其原因,因为这会对我的应用程序造成严重破坏.

/* Drop statements for the table and triggers*/  

IF  EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].   [t_upd_TestTrigger_002]'))
    DROP TRIGGER [dbo].[t_upd_TestTrigger_002]
IF  EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[t_upd_TestTrigger_002]'))
    DROP TRIGGER [dbo].[t_upd_TestTrigger_001]
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TestTrigger]') AND type in (N'U'))
    DROP TABLE [dbo].[TestTrigger]


CREATE TABLE [dbo].[TestTrigger] /*Creating a test table*/
(
    [InternalKey] INT  NOT NULL,
    [UserModified] varchar(50) DEFAULT SUSER_SNAME()
) 


/* Please run the snippet below as seperate batch, else you will get 
   an error that 'CREATE TRIGGER' must be the first statement in a 
   query batch.

   CREATING A UPDATE TRIGGER FOR THE TEST TABLE
*/

CREATE TRIGGER [t_upd_TestTrigger_001] ON [dbo].[TestTrigger]
FOR UPDATE
AS
BEGIN
    --This trigger has some business logic which gets executed 
    print 'In Trigger 001 '
END

/* Please run the snippet below as separate batch, else you will 
   get an error that 'CREATE TRIGGER' must be the first statement 
   in a query batch.

   CREATING Another UPDATE TRIGGER FOR THE TEST TABLE 

   This trigger updates the audit fields in the table and it has to be 
   a separate trigger, We cannot combine this with other update triggers - 
   So table TestTrigger will have two FOR UPDATE triggers
*/


CREATE TRIGGER [t_upd_TestTrigger_002] ON [dbo].[TestTrigger]
FOR UPDATE
AS
    print 'bad guy starts'
UPDATE SRC
    SET UserModified = SUSER_SNAME()
    FROM inserted AS INS
    INNER JOIN dbo.[TestTrigger] AS SRC
        ON INS.InternalKey = SRC.InternalKey
        print 'bad guy ends'

/* INSERTING TEST VALUE IN THE TEST TRIGGER TABLE*/

INSERT INTO dbo.[TestTrigger](InternalKey,UserModified)
SELECT 1 ,'Tester1'  UNION ALL
SELECT 2,'Tester2' UNION ALL 
SELECT 3 ,'Tester3'

/* TestTrigger table has 3 records, we will update the InternalKey 
   of first record from 1 to 4.  We would expect following actions
   1) [t_upd_TestTrigger_001] to be executed once
   2) [t_upd_TestTrigger_002] to be executed once
   3) A message that (1 row(s) affected) only once.

   On Execution, i find that [t_upd_TestTrigger_002] internally triggers 
   [t_upd_TestTrigger_001].

   Please note Database level property Recursive Triggers enabled is 
   set to false.
*/

/*UPDATE THE TABLE  SEE THE MESSAGE IN RESULT WINDOW*/
UPDATE dbo.[TestTrigger]
SET InternalKey = 4
WHERE InternalKey = 1
Run Code Online (Sandbox Code Playgroud)

Tom*_*lak 6

"启用递归触发器"不会影响传递触发器.

这意味着如果触发器A以激活触发器B的方式更新表,并且触发器B更新同一个表,以便再次运行触发器A,则SQL Server无法检测和禁止此无限循环.特别是因为触发器B可以更新其他表,并且它们上的触发器可以再次更新原始表 - 这可能会变得像您所希望的那样复杂.

最终,将达到触发器嵌套级别限制,并且循环停止.

我怀疑你的两个触发器都以某种方式更新了源表.如果触发器自行激活,SQL Server只能检测递归触发器.我想你不是这样的.重组触发器是唯一干净的出路.

作为一个(hackery)想法:您可以在表中附加一个字段(数据类型和值无关),该字段由无操作但通过触发器更新.然后更改二阶触发器以更新该字段.IF UPDATE()将该字段的检查添加到您的一阶触发器.如果已设置字段,则防止现在冗余更新.如果这是有道理的.;-)

MSDN:使用嵌套触发器,请参阅"直接递归"和"间接递归"部分.