大多关系型数据库系统:如oracle、sybase、DB2等均支持对数据库触发器(data base triggers)的使用。触发器是一种特殊类型的存贮过程,它在插入、删除或修改特定表中数据时起作用。触发器通过维持不同表中逻辑上相关数据的一致性,保持数据的相关完整性。
触发器的主要特点在于,不管何种原因造成数据变化,它均能够自动响应。因此,与存贮过程相类似,在当今数据库系统的建立中,系统开发人员大多使用触发器,极大推进了系统建立的质量。本文以oracle公司的oracle 7数据库系统所支持的触发器为例,就触发器的创建、组成、使用作一介绍。
1 触发器的创建及使用时机
当针对某特定表的insert,update或delete语句执行时,用户所定义的过程被隐含执行,这个过程就叫做数据库触发器。触发器可以作为一个单元而执行的sql及pl/sql语句,并可调用存贮过程,但存贮过程与触发器在被执行的方式上完全不同。存贮过程是被用户应用触发器显式调用的,而触发器则是当insert,update或delete语句执行时,由数据库系统点火的(fired),不管与其相连的用户及应用程序。触发器被存贮于数据库中,并与相关联的表分离,由于一般应用预先定义了触发器,相应的数据库管理系统对其进行了伪编译及优化,因而在客户/服务器计算模式下,对减轻网络流量及加快执行速度方面,是一较好的方案。
触发器仅可定义于表上,而不能定义于视图上,在大多数情况下,触发器用于如下几个方面:
1) 自动生成派生列值;2) 禁止非法事务;3) 增强复杂的安全识别;4) 在分布式数据库中增强参照完整性;5) 增强复杂的商业规则;6) 提供透明的事件日志;7) 提供高级审计;8) 维护同步表复制;9) 在表存取上聚合统计。
开发人员一般是对上述9种情况作组合使用,可归为以下四种典型应用。
1) 对库中相关表进行连环更新,如:键值的同步更新,数据冗余实现,计算表的同步更新等;
2) 实现那些破坏完整性操作的拒绝,如:不匹配外键值的插入拒绝;
3) 实现库定义本身所不能实现的更为复杂的商业规则,如:更新操作的时间限制,更新数据的幅度限制等;
4) 实现简单的“如果……怎么办”的分析。
在触发器的使用中,需注意避免级联点火的问题,另一方面,对触发器的过度使用会导致维护困难,还需注意触发器级定义完整性约束的区别。
2 触发器的组成
触发器,由触发事件或语句、触发器限制、触发体三部分组成,如下列所示:
能导致触发器点火的SQL语句叫做触发事件或语句,它可以是在一表上的INSERT,UPDATE或DELETE语句,也可以是多个DML语句,如:……INSERT OR DELETE OF INVENTORY……。
当多个类型DML语句点火触发器时,条件前置可用来检测触发语句的类型,因而,单一的触发器内可据点火触发器主句类型来执行不同的处理。
触发器限制指明一布尔型(逻辑)表达式,仅当表达式值为真(TRUE)时,触发器才点火,否则触发体将不被执行。
触发体是一个过程(PL/SQL块),它由一些SQL及PL/SQL语句代码组成,触发语句被执行,且触发器限制为真时,该段代码被执行。
与存贮过程类似,触发体内含SQL及PL/SQL语句,并可定义PL/SQL语言结构,可指明触发体、执行的次数。
行触发器对所影响的每行执行一次。如-UPDATE语句涉及到某表的多行更新,则对更新的每一行,触发器点火一次;而语句触发器仅点火一次,不管其语句影响到表的多少行;如-DELETE语句删除了表中的多行,但语句触发器仅点火一次。
在定义触发器时,还可指明触发时间,即触发体在触发语句之前或之后执行:BEFORE、AFTER。
在触发器的实际应用中,往往是组合触发时间及触发次数,由这些参数可形成如下表所示的四种类型的触发器。
类 型 含 义 触发时间 触发次数
BEFORE Statement 在执行触发语句前,执行触发体
AFTER Statement 在执行触发语句及申请任何滞后完全性约束之后,执行触发体
BEFORE ROW 在修改所影响的每一行及验证相应完整性约束之前,执行触发体
AFTER ROW 在修改所影响的每一行及可能申请相应完整性约束之后,执行触发体,设触发器实行行级封锁机制。
对一给定表,可以有同一类型的多个触发器。更进一步,对每种类型的DML语句(INSERT,UPDATE或DELETE)亦可建立任意多的前缀类型不同的触发器,针对同一语句的相同类型的触发器,其点火次序是随机的(不能实现程序控制)。
3 触发器的执行
定义于数据库的触发器,可由程序控制其使能(ENABLE)或屏蔽(DISABLE)状态。
单一的-SQL语句可以潜在地点火前述四种类型的触发器,另一方面,触发体内的一语句可能导致一个或多个完整性规则,也可能导致其它的触发器点火(级联触发器),关于多触发点火次序及约束检测,ORACLE采用以下的执行模型。
1) 执行所有的BEFORE语句级触发器;2) 对遍历所涉及的每一行:a.执行所有的BEFORE行级触发器;b.锁定并修改行,执行完整性约束检测;c.执行所有的AFTER行级触发器。3) 完成滞后完整性的约束检测;4) 执行所有的AFTER语句级触发器。
仅当整个执行模型成功之后,触发语句执行成功,否则在有例外代码指定的情况下,整个事务被退回。因而完整性约束定义不能与触发器定义相矛盾
触发器的主要特点在于,不管何种原因造成数据变化,它均能够自动响应。因此,与存贮过程相类似,在当今数据库系统的建立中,系统开发人员大多使用触发器,极大推进了系统建立的质量。本文以oracle公司的oracle 7数据库系统所支持的触发器为例,就触发器的创建、组成、使用作一介绍。
1 触发器的创建及使用时机
当针对某特定表的insert,update或delete语句执行时,用户所定义的过程被隐含执行,这个过程就叫做数据库触发器。触发器可以作为一个单元而执行的sql及pl/sql语句,并可调用存贮过程,但存贮过程与触发器在被执行的方式上完全不同。存贮过程是被用户应用触发器显式调用的,而触发器则是当insert,update或delete语句执行时,由数据库系统点火的(fired),不管与其相连的用户及应用程序。触发器被存贮于数据库中,并与相关联的表分离,由于一般应用预先定义了触发器,相应的数据库管理系统对其进行了伪编译及优化,因而在客户/服务器计算模式下,对减轻网络流量及加快执行速度方面,是一较好的方案。
触发器仅可定义于表上,而不能定义于视图上,在大多数情况下,触发器用于如下几个方面:
1) 自动生成派生列值;2) 禁止非法事务;3) 增强复杂的安全识别;4) 在分布式数据库中增强参照完整性;5) 增强复杂的商业规则;6) 提供透明的事件日志;7) 提供高级审计;8) 维护同步表复制;9) 在表存取上聚合统计。
开发人员一般是对上述9种情况作组合使用,可归为以下四种典型应用。
1) 对库中相关表进行连环更新,如:键值的同步更新,数据冗余实现,计算表的同步更新等;
2) 实现那些破坏完整性操作的拒绝,如:不匹配外键值的插入拒绝;
3) 实现库定义本身所不能实现的更为复杂的商业规则,如:更新操作的时间限制,更新数据的幅度限制等;
4) 实现简单的“如果……怎么办”的分析。
在触发器的使用中,需注意避免级联点火的问题,另一方面,对触发器的过度使用会导致维护困难,还需注意触发器级定义完整性约束的区别。
2 触发器的组成
触发器,由触发事件或语句、触发器限制、触发体三部分组成,如下列所示:
能导致触发器点火的SQL语句叫做触发事件或语句,它可以是在一表上的INSERT,UPDATE或DELETE语句,也可以是多个DML语句,如:……INSERT OR DELETE OF INVENTORY……。
当多个类型DML语句点火触发器时,条件前置可用来检测触发语句的类型,因而,单一的触发器内可据点火触发器主句类型来执行不同的处理。
触发器限制指明一布尔型(逻辑)表达式,仅当表达式值为真(TRUE)时,触发器才点火,否则触发体将不被执行。
触发体是一个过程(PL/SQL块),它由一些SQL及PL/SQL语句代码组成,触发语句被执行,且触发器限制为真时,该段代码被执行。
与存贮过程类似,触发体内含SQL及PL/SQL语句,并可定义PL/SQL语言结构,可指明触发体、执行的次数。
行触发器对所影响的每行执行一次。如-UPDATE语句涉及到某表的多行更新,则对更新的每一行,触发器点火一次;而语句触发器仅点火一次,不管其语句影响到表的多少行;如-DELETE语句删除了表中的多行,但语句触发器仅点火一次。
在定义触发器时,还可指明触发时间,即触发体在触发语句之前或之后执行:BEFORE、AFTER。
在触发器的实际应用中,往往是组合触发时间及触发次数,由这些参数可形成如下表所示的四种类型的触发器。
类 型 含 义 触发时间 触发次数
BEFORE Statement 在执行触发语句前,执行触发体
AFTER Statement 在执行触发语句及申请任何滞后完全性约束之后,执行触发体
BEFORE ROW 在修改所影响的每一行及验证相应完整性约束之前,执行触发体
AFTER ROW 在修改所影响的每一行及可能申请相应完整性约束之后,执行触发体,设触发器实行行级封锁机制。
对一给定表,可以有同一类型的多个触发器。更进一步,对每种类型的DML语句(INSERT,UPDATE或DELETE)亦可建立任意多的前缀类型不同的触发器,针对同一语句的相同类型的触发器,其点火次序是随机的(不能实现程序控制)。
3 触发器的执行
定义于数据库的触发器,可由程序控制其使能(ENABLE)或屏蔽(DISABLE)状态。
单一的-SQL语句可以潜在地点火前述四种类型的触发器,另一方面,触发体内的一语句可能导致一个或多个完整性规则,也可能导致其它的触发器点火(级联触发器),关于多触发点火次序及约束检测,ORACLE采用以下的执行模型。
1) 执行所有的BEFORE语句级触发器;2) 对遍历所涉及的每一行:a.执行所有的BEFORE行级触发器;b.锁定并修改行,执行完整性约束检测;c.执行所有的AFTER行级触发器。3) 完成滞后完整性的约束检测;4) 执行所有的AFTER语句级触发器。
仅当整个执行模型成功之后,触发语句执行成功,否则在有例外代码指定的情况下,整个事务被退回。因而完整性约束定义不能与触发器定义相矛盾
有如下触发器:
CREATE TRIGGER tri_UpdateJobTime
ON 招聘表
FOR UPDATE
AS
BEGIN
UPDATE 招聘表 SET 更新日期=GETDATE()
WHERE 招聘id=Inserted.招聘id
END
按道理来讲,这个触发器会导致死循环,但是实际应用时,却没发现任何异样。
在查询分析器里,执行
Update 招聘表 set 工作年限=2 where 招聘id=1
时,显示影响一行,但是更新日期会被更新。
如果将触发器改为:
CREATE TRIGGER tri_UpdateJobTime
ON 招聘表
FOR UPDATE
AS
BEGIN
if not update(更新日期)
UPDATE 招聘表 SET 更新日期=GETDATE() from 招聘表 a,inserted b WHERE a.招聘id=b. 招聘id
END
则执行以上更新会显示影响2行。更新日期也会更新。
我想问一下,到底第一种写法会不会导致死循环?
为什么更新时显示影响1行?
CREATE TRIGGER tri_UpdateJobTime
ON 招聘表
FOR UPDATE
AS
BEGIN
UPDATE 招聘表 SET 更新日期=GETDATE()
WHERE 招聘id=Inserted.招聘id
END
按道理来讲,这个触发器会导致死循环,但是实际应用时,却没发现任何异样。
在查询分析器里,执行
Update 招聘表 set 工作年限=2 where 招聘id=1
时,显示影响一行,但是更新日期会被更新。
如果将触发器改为:
CREATE TRIGGER tri_UpdateJobTime
ON 招聘表
FOR UPDATE
AS
BEGIN
if not update(更新日期)
UPDATE 招聘表 SET 更新日期=GETDATE() from 招聘表 a,inserted b WHERE a.招聘id=b. 招聘id
END
则执行以上更新会显示影响2行。更新日期也会更新。
我想问一下,到底第一种写法会不会导致死循环?
为什么更新时显示影响1行?
replay:
第一种写法不会导致死循环,可能是由于数据库服务器
“知道”此种情况如果按常规处理很显然的会导致死循环,
所以一个触发器中的的UPDATE语句不会再次触发该触发器
自身的执行。
如果你在用第一种写法为同一个加上两个相同内容的触发器,
则必然导致死循环(在SQL SERVER中由于存储过程最多嵌套
32层,所以会导致错误。)
假设有两个表,如果你在表1上的UPDATE触发器中修改了表2
中的内容,同时表2上的UPDATE触发器也修改了表1中的内容,
并且你的触发器也是按你的第一种情况写的,那么必定导致
递归调用,并导致错误。
我的建议是总是采用第二种写法,并要密切注意触发器的
递归触发问题,这常常是触发器容易带来的“陷阱”。
另外,在SQL SERVER中,一条外部的UPDATE语句,无论修改了
多少行记录,都只触发该表上的UPDATE触发器一次,也就是
UPDATE型的触发器不是按每行触发一次执行的。
“知道”此种情况如果按常规处理很显然的会导致死循环,
所以一个触发器中的的UPDATE语句不会再次触发该触发器
自身的执行。
如果你在用第一种写法为同一个加上两个相同内容的触发器,
则必然导致死循环(在SQL SERVER中由于存储过程最多嵌套
32层,所以会导致错误。)
假设有两个表,如果你在表1上的UPDATE触发器中修改了表2
中的内容,同时表2上的UPDATE触发器也修改了表1中的内容,
并且你的触发器也是按你的第一种情况写的,那么必定导致
递归调用,并导致错误。
我的建议是总是采用第二种写法,并要密切注意触发器的
递归触发问题,这常常是触发器容易带来的“陷阱”。
另外,在SQL SERVER中,一条外部的UPDATE语句,无论修改了
多少行记录,都只触发该表上的UPDATE触发器一次,也就是
UPDATE型的触发器不是按每行触发一次执行的。
268

被折叠的 条评论
为什么被折叠?



