课上的一个ppt
-------------------------------
与触发器相关的数据库选项与参数
递归选项:ON/OFF
recursive triggers:该参数可以限制直接递归,但不能限制间接递归;
嵌套参数:1-32?
nested triggers:SQL Server 2000规定一个触发器最多只能嵌套32层。最多层可设置吗?
上机练习2
在SQL Server 2000或其他数据库系统中利用具体的实例测试与触发器有关的数据库选项和参数的设置对触发器工作机制的影响。
各位有没有关于这方面的测试的例子?感谢

解决方案 »

  1.   

    如何控制MSSQL触发器递归
    作者:邹建  2007-08-22 
    背景
    A表UPDATE后,取B表某列再次UPDATE A表,这样又触发了A表的 UPDATE  触发器,我的目的是只触发一次,是否设置 nested triggers 选项关闭递归触发器即可?
    分析
    首先,必须清楚触发器递归的定义,触发器有两种递归方式:
    1.     直接递归
    A表上的触发器更改(插入/删除/更新)A表数据,导致A表的触发器再次触发,这种状况称之为直接递归;
    2.     间接递归
    A表上的触发器更新B表数据,导致触发B表触发器;而B表触发器又更改A表数据,导致A表触发器再次触发,这种状况称之为间接递归
    解决方法—选项配置(影响所有范围的触发器)
    SQL Server提供了数据库级和服务器级配置来确定递归触发器是否被允许:
    1.       服务器级(使用存储过程sp_configure 进行配置)
    server trigger recursion 选项(SQL Server 2005)决定是否允许服务器级触发器直接递归激发;当此选项设置为1 (ON,默认值)时,将允许服务器级触发器递归激发;当设置为0 (OFF) 时,服务器级触发器不能递归激发。
    nested triggers选项决定是否允许触发器间接递归激发;当此选项设置为1 (ON,默认值)时,将允许触发器递归激发;当设置为0 (OFF) 时,触发器不能递归激发。
    2.       数据库级
    RECURSIVE_TRIGGERS数据库选项设置决定是否允许数据库中的触发器直接递归触发;默认值为OFF,不允许直接递归触发。
    该选项可以通过存储过程sp_dboption设置;对于SQL Server 2005,还可以使用类似下面的T-SQL设置:
    ALTER DATABASE [DbName]
        SET RECURSIVE_TRIGGERS ON
    使用选项决定递归触发器的行为时,需要注意的是选项设置的有效范围:
    nested triggers选项决定所有的触发器是否间接递归激发,这意味着这是一个SQL Server实例级的选项,设置将影响所有的触发器。
    server trigger recursion选项是SQL Server 2005中才有的(SQL Server 2005才有服务器级触发器)。
    RECURSIVE_TRIGGERS选项影响配置它的数据库中的所有触发器。
    其他解决方法(针对特定的触发器)
    如果只希望特定的触发器允许或者禁止触发器,则SQL Server没有选项可以做到;如果确实需要这样的功能,可以在触发器代码中实现控制:
    1.       使用update(列名)函数
    此函数适用于对 UPDATE 的控制。对于"A表UPDATE 后,取B表某列再次UPDATE A表",如果仅更新A表的某些列才触发UPDATE B, 并且B 表再次UPDATE A表不会包含A表触发UPDATE B的那些列,则在A表的触发器中,使用IF UPDATE(列)来确定是否应该UPDATE B即可。
    2.       使用@@NESTLEVEL
    该变量值确定嵌套层数。
    对于"A表update后,取B表某列再次UPDATE A表",如果触发者不是一个存储过程, 则UPDATE A 的A表触发器@@NESTLEVEL = 1, 到UPDATE B时, B表触发器 @@NESTLEVEL = 2, B表触发器再UPDATE A时, @@NESTLEVEL = 3。
    所以如果 @@NESTLEVEL >=3 时, 一般表示递归了(当然, 前提是UPDATE A的触发器本身没有两层的递归, 即不能是存储过程再调用存储过程去UPDATE A。
    3.       使用 @@PROCID
    该全局变量返回调用者的object_id。如果需要A表触发B表触发器,而B表触发器再触发A表触发器时,A表触发器不响应;则在A表触发器中使用它来判断触发者是谁,如果是B表触发器,则不处理就行了,类似下面这样:
    IF OBJECT_ID(N'B表触发器名称') = @@PROCID
    BEGIN
        PRINT 'B表触发器, 不处理'
        RETURN
    END
      

  2.   

    使用间接递归时,应用程序更新表 T1,从而激发触发器 TR1,该触发器更新表 T2。在这种情况下,触发器 T2 将激发并更新 T1。使用直接递归时,应用程序更新表 T1,从而激发触发器 TR1,该触发器更新表 T1。由于表 T1 被更新,触发器 TR1 再次激发,依此类推。