日期:2014-05-18  浏览次数:20648 次

【T-MAC学习笔记19之--浅谈触发器】
很难排版 有些东西 没写在帖子里
请看原来的地址
http://blog.csdn.net/feixianxxx/archive/2009/12/03/4935151.aspx

这次谈的是触发器
Microsoft SQL Server 提供两种主要机制来强制使用业务规则和数据完整性:约束和触发器。

关于触发器和约束用谁比较好,这主要看业务的逻辑复杂程度.
如果你的处理逻辑比较简单,并且可以用一些简单的约束来处理,则应该尽量使用PRIMARY KEY ,UNIQUE CHECK这些约束.
当约束支持的功能无法满足应用程序的功能要求时,DML 触发器非常有用 例如:
1.除非 REFERENCES 子句定义了级联引用操作,否则 FOREIGN KEY 约束只能用与另一列中的值完全匹配的值来验证列值
2.约束只能通过标准化的系统错误消息来传递错误消息。如果应用程序需要(或能受益于)使用自定义消息和较为复杂的错误处理,则必须使用触发器。
3.DML 触发器可以防止恶意或错误的 INSERT、UPDATE 以及 DELETE 操作,并强制执行比 CHECK 约束定义的限制更为复杂的其他限制。
check约束只能检查引用表内的列,当涉及外表的一些规则时候 需要在本表里使用trigger.
4.如果触发器表上存在约束,则在 INSTEAD OF 触发器执行后但在 AFTER 触发器执行前检查这些约束。
  如果违反了约束,则回滚 INSTEAD OF 触发器操作并且不执行 AFTER 触发器。
5.一个表中的多个同类 DML 触发器(INSERT、UPDATE 或 DELETE)允许采取多个不同的操作来响应同一个修改语句。

触发器分类:(- -|| 这个分类 可能是错的 )
1.DDL触发器:当服务器或数据库中发生数据定义语言 (DDL) 事件时将调用 DDL 触发器
2.登录触发器:将为响应 LOGON 事件而激发存储过程。与 SQL Server 实例建立用户会话时将引发此事件。
3.DML触发器:当数据库中发生数据操作语言 (DML) 事件时将调用 DML 触发器
这个类型触发器还可以分成:
AFTER 触发器:在执行了INSERT、UPDATE 或 DELETE 语句操作之后执AFTER 触发器(指定 AFTER 与指定 FOR 相同)
INSTEAD OF 触发器 :执行 INSTEAD OF 触发器代替通常的触发动作。还可为带有一个或多个基表的视图定义 INSTEAD OF 触发器
clr触发器:CLR 触发器可以是 AFTER 触发器或 INSTEAD OF 触发器。CLR 触发器还可以是 DDL 触发器。
CLR 触发器将执行在托管代码(在 .NET Framework 中创建并在 SQL Server 中上载的程序集的成员)中编写的方法

先来说说我们最常用的DML触发器

这里只介绍DML中的 AFTER触发器和INSTEAD OF触发器.
首先列出2者的不同点:这里内容忽略了 
这里由于排排版排布好 请看我的原文地址


触发时间:(上面对比里说了,再强调下)
AFTER触发器:在处理触发操作(INSERT、UPDATE 或 DELETE)、INSTEAD OF 触发器和约束之后激发。
  ps:因为是在约束后激发,因此触发器里不可以进行违反约束的操作,这样会使约束失去效果.
INSTEAD OF触发器:将在处理约束前激发,以替代触发操作。如果表有 AFTER 触发器,它们将在处理约束之后激发。
  如果违反了约束,将回滚 INSTEAD OF 触发器操作并且不执行 AFTER 触发器
   
创建一个触发器的几点:(MSDN)
1.CREATE TRIGGER 语句必须是批处理中的第一个语句,该语句后面的所有其他语句被解释为 CREATE TRIGGER 语句定义的一部分。
2.创建 DML 触发器的权限默认分配给表的所有者,且不能将该权限转给其他用户。
3.DML 触发器为数据库对象,其名称必须遵循标识符的命名规则。
4.虽然 DML 触发器可以引用当前数据库以外的对象,但只能在当前数据库中创建 DML 触发器。
5.虽然 DML 触发器可以引用临时表,但不能对临时表或系统表创建 DML 触发器。不应引用系统表,而应使用信息架构视图。
6.对于含有用 DELETE 或 UPDATE 操作定义的外键的表,不能定义 INSTEAD OF DELETE 和 INSTEAD OF UPDATE 触发器。
7.虽然 TRUNCATE TABLE 语句类似于不带 WHERE 子句的 DELETE 语句(用于删除所有行),但它并不会触发 DELETE 触发器,因为 TRUNCATE TABLE 语句没有记录。
8.WRITETEXT 语句不会触发 INSERT 或 UPDATE 触发器。
9.尽量不要在触发器里面返回结果.这是因为对这些返回结果的特殊处理必须写入每个允许对触发器表进行修改的应用程序中(未来版本的 SQL Server 中会删除从触发器返回结果集的功能)

触发器的延迟的名称解析
还记得上一个笔记的存储过程的延迟的名称解析,它在触发器中一样适用的.
你可以在触发器中适用还没有定义的表,触发器回等到第一次触发触发器的时候编译并且检查内部的表.这个时候如果还不存在,那就出错了.
  如果 DML 触发器引用的对象已删除或重命名,则执行触发器时也会返回错误。
  如果 DML 触发器中引用的对象被替换为同名对象,则不必重新创建即可执行触发器。
 
触发器触发的先后
如果一个表上的DML操作的一个类型对应了多个触发器,则谁先触发呢?
你可以通过sp_settriggerorder这个存储过程 指定对应操作触发器的第一个触发和最后一个触发(INSTEAD OF触发器除外)
例:sp_settriggerorder @triggername = 'MyTrigger', @order = 'first', @stmttype = 'UPDATE' 具体用法参考MSDN
ps:不能将 INSTEAD OF 触发器指定为第一个或最后一个触发器,因为它可能激发表的AFTER触发器.

触发器的整体性(指事务方面)
SQL code
create table a (id int,value1 int)
    create table b (id int,value2 int )
    go
    --建立在b上的触发器
    create trigger b_t on b 
    after insert 
    as
    rollback;
    print 'no'
    go
    --在一个事务里执行操作
    begin tran 
        insert a select 1,2
        insert b select 3,4
    commit tran
    --插入B表操作 触发AFTER触发器 
    --因为触发器的操作属于事务的一部分,触发器内又有回滚操作,所以回滚整个事务
    select * from a
    /*
    id          value1
    ----------- -----------
    
    (0 行受影响)*/
    
    --如果不是在事务内进行 仅仅回滚触发器内的操作和触发操作
        insert a select 1,2
        insert b select 3,4
     select * from a
     /*
     id          value1
    ----------- -----------
    1           2*/


触发器中的2张特殊表--Inserted 和 Deleted
Inserted表包含的是update 和 insert 操作保留的数据(AFTER 是操作后的数据