5.3.3 何时不用触发器
触发器有很多合适的用途,例如我们刚刚在5.3.2节中看到的那些,然而有一些场合最好用别的技术来处理。比如,我们可以用触发器替代级联特性来实现外码约束的on delete cascade
特性。然而这样不仅需要完成更大的工作量,而且使数据库中实现的约束集合对于数据库用户来说更加难以理解。
举另外一个例子,可以用触发器来维护物化视图。例如,如果我们希望能够快速得到每节课所注册的学生总数,我们可以创建一个关系来实现这个功能:
1 | section_registration( course_id, sec_id, semester, year, total_students); |
它由以下查询所定义:
1 | select course_id, sec_id, semester, year, count(ID) as total_students |
在对关系takes
进行插入
、删除
或更新
时,每门课的total_students
的值必须由触发器来维护到最新状态。维护时可能要对section_regustration
做插入
、更新
或删除
,这些都相应地写在触发器里。
然而,许多数据库现在支持物化视图,由数据库系统自动维护(见4.2.3节)。因此没必要编写代码让触发器来维护这样的物化视图。
触发器也被用来复制或者备份数据库;在每一个关系的插入、删除或更新的操作上创建触发器,将改变记录在称为change
或deta
的关系上。一个单独的进程将这些改变复制到数据库的副本。然而,现代的数据库系统提供内置的数据库复制工具,使得复制在大多数情况下不必使用触发器。本书将在第19章详细讨论复制数据库。
触发器的另一个问题是当数据从一个备份的拷贝中加载,或者一个站点上的数据库更新复制到备份站点的时候,触发器动作的非故意执行。在该情况下,触发器动作已经执行了,通常不应该再次执行。在加载数据的时候,触发器应当显式设为无效。对于要接管主系统的备份复制系统,触发器应该一开始就设为无效,而在备份站点接管了主系统的业务后,再设为有效。作为取代的方法,一些数据库系统允许触发器定义为not for replication
,保证触发器不会在数据库备份的时候在备份站点执行。另一些数据库系统提供了一个系统变量用于指明该数据库是一个副本,数据库动作在其上是重放;触发器会检查这个变量,如果为真则退出执行。这两种解决方案都不需要显式地将触发器设为失效或有效。
写触发器时,应特别小心,这是因为在运行期间一个触发器错误会导致引发该触发器的动作语句失败。而且,一个触发器的动作可以引发另一个触发器。在最坏的情况下,这甚至会导致一个无限的触发链。例如,假设在一个关系上的插入触发器里有一个动作引起在同一关系上的另一个(新的)插人,该新插入动作也会引起另一个新插人,如此无穷循环下去。有些数据库系统会限制这种触发器链的长度(例如16或32),把超过此长度的触发器链看作是一个错误。另一些系统把引用特定关系的触发器标记为错误,对该关系的修改导致了位于链首的触发器被执行。
原文链接: 5.3.3 何时不用触发器