触发器综述
使用触发器很多年了,从6.5到2005,从当时为了查错被迫使用触发器跟踪到现在用触发器实现复杂的业务逻辑。有必要对触发器的写法及注意事项做一个总结。
对于触发器,很多人认为不要使用,主要的原因是有触发器不好控制和触发器影响性能的说法。但是我认为,触发器作为大型数据库的组成部分,并不是只有SQL SERVER才有,它的一些功能是其它方法无法代替的,特别是它作为数据库约束的补充,所能进行的业务规则的约束,以及在跟踪和同步所能起的作用。
个人认为,触发器确实不好控制,这是因为:
一、 触发器实现的是在表的操作进行同时,自动进行的操作或者控制,在写触发器代码时必须考虑其特殊性。
二、 必须限定触发器影响的记录,不能扩大。也就是说必须引用INSERTED和DELETED两个虚表限定操作的范围。
三、 INSERTED和DELETED的作用域只限定触发器本身,其调用的存储过程是不能使用的。
四、 写触发器必须考虑性能,因为其自动性,如果触发器性能不好是可能拖垮一个系统的。
五、 必须考虑一次操作多条记录的情况,除非保证一次只操作一条记录,一般不能用变量暂存虚表的数据,否则就可能出现在批量操作情况下,触发器只处理最后一条记录的情况,这类错误可以说是触发器最常见的错误之一。
六、 必须注意递归和嵌套触发器,因为触发器往往需要修改其他或者本表数据来实现其功能,这里的修改数据往往能再次触发触发器,这时就必须保证其嵌套或者递归过程不是无限的,SQL SERVER对触发器的嵌套层数有最多32的限制。
七、 触发器不好调试,比起一般存储过程,触发器是在修改数据过程中触发,调试难度更大。调试过程必须考虑所有情况,比如空表插入数据、已有数据插入新数据、一次插入多行数据、修改一条数据、修改多条数据、一次删除多条数据、影响0行的修改或者删除语句等等。
触发器不好控制,这就要求我们在决定是否使用触发器的时候需要非常谨慎,个人认为,对于约束功能,如果可以用其他数据库方法实现的,比如可以用唯一约束、外键约束、规则约束、不可空约束实现的约束,就不要用触发器,触发器只用来完成这些方法实现不了的约束。对于可以用触发器完成的跟踪、同步功能,则要考虑是否必要,必要的时候才用。而对于其他功能,比如统计功能,则需要与客户端实现的优劣进行比较。
对于触发器影响性能的说法,我不是很同意,因为在触发器代码写得没有问题的前提下,触发器所做的工作并不是多余的,这些功能如果不在触发器完成,就必须在存储过程或者客户端用其他代码实现,所以在系统负担上基本是一样的。触发器唯一比其他方法实现多消耗的是触发器作为特殊的存储过程,必须有个被调用的过程,但是由于SQL SERVER有存储过程的预编译和过程缓存的机制,这方面的开销不会很多。相反,在某些情况下,由于触发器是在记录更改过程执行的,可以把某些服务器的负载分散到多个时间点去执行,一定程度上均衡服务器负担,从而提高整体的性能。
我想通过对触发器在应用上的分类来说明触发器如何使用,以及使用过程中需要注意的事项。这里需要说明的是,我的分类并不是从技术以及触发器类型来分,而是根据触发起完成的功能来分。(篇幅关系,我把本文分成多个博文,主要的说明和举例将在各个分类的博文中描述,这里只是简单的介绍)
一、约束类触发器。
这类触发器的主要功能是实现不能用主键约束、唯一性约束、外键约束、CHECK约束、DEFAULT约束、NOT NULL约束来实现的数据库的完整性和一致性需求,以及其他限制性的业务规则。
二、日志类触发器。
这类触发器按要求记录必要的系统运行数据,为程序查错和业务流程优化提供帮助。
三、同步类触发器。
这类触发器可以实现不同系统之间的数据同步,也可以实现一些数据的特殊转换。
四、统计类触发器。
这类触发器可以实现在数据录入同时统计必要的数据。
五、综合类触发器。
综合类触发器是以上四类触发器的综合,也就是一个触发器完成上述四类功能的某几类功能。
这里不再展开了,举个简单的例子,有兴趣的可以自己来实现下,在统计类触发器中,我举了个库存统计的例子,如果加多个要求,就是要求进货表和出货表的数据变化,不能使得库存数据产生负数,这样触发器代码中就必须加入约束类触发器的代码。
六、视图触发器。
视图触发器有其特殊性,使用视图触发器可以更好的完成视图数据的增删改。
七、其他触发器。
其他触发器包括一些其他功能的触发器,比如2005版本增加的DDL触发器,DDL触发器是在执行DDL语句的时候触发,可以用来做必要的限制和记录日志,其功能类似于约束类触发器或者日志类触发器。2008版本增加的登录触发器功能貌似与DDL触发器类似,还没有做研究,只顺便提一下,错了莫怪。
也有一些功能比较特殊的触发器,很少有这类例子,所以不单独写一个博文了,有兴趣的可以看看《触发器和作业结合》,这是之前在论坛遇到的一个特殊例子。
后记:这篇文章写了很长时间,内容也比较多,错漏和前后不一可能在所难免,敬请谅解。也欢迎提出错处,我会尽快更正的。