资源描述
单击此处编辑母版标题样式,*,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,Oracle SQL&PL/SQL,第,24,章,数据库触发器,本章要点,理解数据库触发器、变异表和约束表的概念及数据库触发器的语法,掌握如何在,SQL*PLUS,中创建和测试,DML,触发器、,instead-of,数据库触发器以及系统触发器,了解数据库触发器的使用时机和限制。,触发器的类型,触发器主要有三种类型:,DML,INSTEAD-OF,触发器,系统触发器。,主要用于:,维护那些通过创建表时的声明约束无法实现的复杂的完整性约束。,通过记录已进行的改变以及是谁进行了该项改变来检查一个表中的信息。,当一个表发生改变时,自动向其他程序发送需要采取行动的信号。,在一个发布,-,预订环境中发布有关各种事件的信息。,DML,触发器,DML,触发器可以由,DML,语句激发,由,DML,语句的类型决定,DML,触发器的类型。,DML,触发器可以在,DML,语句操作之前或之后激发。,DML,触发器也可以在行或语句操作上激发。,创建触发器,CREATE OR REPLACE TRIGGER trigger_name,BEFORE|AFTER|INSTEAD OF triggering_event,referencing_clause,WHEN trigger_condition,FOR EACH ROW,trigger_body;,所有触发器,不管类型如何,创建语法是相同的,triggering_event,指定激发触发器的表以及列的名称(也可能包括特定的表或视图,),,referencing_clause,被用来引用在行中目前被一个不同的名字修改的数据。有,WHEN,,触发器体只有在条件为真时才会执行。,创建,DML,触发器,触发器中的所有代码将随触发语句一起作为同一事务的一部分执行。,DML,触发器激发顺序,如果存在语句之前的触发器,先执行该触发器。,对于受语句影响每一行:,如果存在行之前的触发器,执行该触发器。,执行该语句本身。,如果存在行之后的触发器,执行该触发器。,如果存在语句之后的触发器,运行该触发器。,DML,触发器激发顺序,当每一个触发器被激发时,该触发器将查看较早的触发器所进行的改变,以及到目前为止由,DML,语句对数据库所进行的任何改变。这一切可以通过每一个触发器所打印的计数器值看到。,相同类型的触发器被激发的顺序没有进行定义。,行级别触发器的相关标识符,触发语句处理每一行时,行级别触发器都激发一次。,在触发器内部,可以通过相关标识符,:old,和,:new,访问正在处理中的行的数据。,PL/SQL,编译器将把这种变量按记录类型处理:,triggering_table%ROWTYPE.,triggering_table,是触发器为之定义的表,引用 :,new.field :old.field,标识符,:old,和,:new,也被称为伪记录。,:,old,和,:new,相关标识符,注意,:old,标识符对,INSERT,语句未定义,而,:new,标识符对,DELETE,语句未定义。,PL/SQL,编译器不会对在,INSERT,语句中使用的,:old,和在,DELETE,语句中使用的,:new,标识符报错,编译的结果将使这两者的字段值为,NULL,。,:,old,和,:new,相关标识符,对:,new,的,修改只能在行级别之前的触发器中进行。不能在行级别之后的触发器改变:,new,,原因是该语句已经进行过处理。,:,old,具有只读属性,只能读取,永远不会被修,改,:,new,和:,old,记录只在行级别触发器内部有效。试图在语句级别触发器内部引用:,new,和:,old,,编译器将报错。,REFERENCING,子句,该语句用在触发器事件之后以及,WHEN,子句之前,语法:,REFERENCING OLD AS old_nameNEW AS new_name,WHEN,子句,WHEN,子句只适用于行级别触发器。,如果使用该子句,触发器体将只对满足由,WHEN,子句指定条件的行而执行。,语法:,WHEN trigger_condition,触发器谓词,INSTEAD-OF,触发器,INSTEAD-OF,触发器是行级别的,执行时,激发它的,DML,语句不执行。,只能定义在视图上(可以是关系型或是对象)。,Oracle8,及更高版本才提供。,创建,instead-of,触发器,instead-of,触发器用于以下两种情况:,允许修改一个本来无法修改的视图。,修改视图中嵌套表列的列。,可更改的与不可更改的视图,可更改视图:可以发出,DML,命令的视图。一般来说,视图如果不包括下列命令中的任何一项,它就是一个可更改视图。,1,、集合操作符(,UNION,、,UNION ALL,、,MINUS,),2,、聚集函数(,SUM,、,AVG,等),3,、,GROUP BY,、,CONNECT BY,或,START WITH,子句,4,、,DISTINCT,操作符,5,、连接,可更改连接视图的条件,如果一个表与另一个表连接之后,其原始表中的关键字在连接后的表中仍然是关键字,那么该表就是一个关键字预留表。,如果一个视图是不可更改的,则可以在其上编写一个,instead-of,触发器来执行正确的操作,从而使该视图可更改。,如果需要进行其他处理的话,也可以在可更改视图上编写,instead-of,触发器。,系统触发器,系统触发器在发生诸如数据库启动或关闭等系统事件时激发,而不是在执行,DML,语句时激发。,系统触发器也可以在,DDL,操作时,如表的创建时被激发。,创建系统触发器,系统触发器可以在两种不同种类的事件(即,DDL,或数据库)上激发。,DDL,事件包括,CREATE,、,ALTER,或,DROP,语句。,而数据库事件包括服务器的启动或关闭,用户的登录或退出,以及服务器错误。,语法:,CREATE OR REPLACE TRIGGER schema.trigger_name,BEFORE|AFTER,ddl,_event_list|database_event_list,ON DATABASE|schema.SCHEMA,when_clause,trigger_body;,系统,DDL,和数据库事件,数据库与模式触发器,系统触发器可以在数据库级别或模式级别定义。,数据库级别的触发器不管触发事件何时发生都将激发,而模式级别触发器只有在指定的模式的触发事件发生时才会激发。,DATABASE,和,SCHEMA,关键字决定了给定系统触发器的级别。如果没有用关键字,SCHEMA,来说明模式,则它就是拥有该触发器的默认模式。,事件属性函数,事件属性函数属系统触发器内部,使用。,这些函数允许触发器获得有关触发事件的信息。,事件属性函数是,SYS,拥有的独立,PL/SQL,函数。,在程序中使用事件属性函数必须在它们的前面加上前缀,SYS,。,事件属性函数列表说明,使用,SERVERERROR,事件,SERVERERROR,事件可以用于跟踪数据库中发生的错误。,错误代码可以使用触发器内部的,SERVER_ERROR,属性函数取出。,该函数只能确定堆栈中的错误码。但不能返回与该错误码相关的错误信息。,系统触发器和事务,系统触发器的事务行为与触发事件有关。系统触发器可以作为基于触发器正常结束时提交的独立事务激发,也可以作为当前用户事务的一部分激发。,STARTUP,,,SHUTDOWN,,,SEVERERROR,和,LOGON,触发器都是由独立事务激发的,而,LOGOFF,和,DDL,触发器则作为当前事务的一部分被激发。,触发器实现的任务将被提交处理。在使用,DDL,触发器的情况下,当前事务(也就是,CREATE,、,ALTER,或,DROP,语句)将自动提交。,LOGOFF,触发器的操作也将作为会话中最后事务的一部分提交。,系统触发器和,WHEN,子句,系统触发器可以使用,WHEN,子句来指定触发器激发条件。然而,对每一种系统触发器所指定的条件类型有如下限制:,STARTUP,和,SHUTDOWN,触发器不能带有任何条件。,SERVERERROR,触发器只可以使用,ERRNO,测试来检查具体错误。,LOGON,和,LOGOFF,触发器可以使用,USERID,或,USERNAME,测试来检查用户标识符或用户名。,DDL,触发器可以检查正在被修改的对象的名称和类型。,其他触发器问题,触发器名称的命名空间(,Name-space,),使用触发器的各种限制和不同种类的触发器体。,与触发器有关的权限问题,触发器名称,命名空间:是一组合法的可供对象作为名字使用的标识符。过程、包和表都共享同一个命名空间,在一个数据库模式范围内,同一命名空间内的所有的对象必须具有唯一的名称。,触发器隶属于一个独立的命名空间。也就是说,触发器可以有与表和过程相同的名称。然而,在一个模式范围内,给定的名称只能用于一个触发器。,对触发器的限制,触发器不能发出任何事务控制语句,如,COMMIT,、,ROLLBACK,、,SAVEPOINT,或,SET TRANSACTION,。,由触发器体调用的任何过程或函数都不能发出任何事务控制语句(除非在,Oracle8i,及更高版本中把它们声明为自治的)。,触发器体不能声明任何,LONG,或,LONG RAW,变量。而且,,:new,和,:old,也不能指向为之定义的表的,LONG,或,LONG RAW,类型的列。,在,Oracle8,及更高版本中,触发器体中的代码可以引用和使用,LOB,(大型对象)列,但不能修改该列的值。这个限制也适用于对象列。,触发器体,在,Oracle8i,之前的版本中,触发器体必须是,PL/SQL,语句块。,在,Oracle8i,及更高版本中,触发器体可以包括,CALL,语句,被调用的过程既可以是,PL/SQL,存储子程序,也可以是,C,语言或,Java,例程的包装器。这就允许你在以,Java,编写的函数代码处创建触发器。,触发器权限,触发器与数据字典,类似于存储子程序,某些数据字典视图也包括了有关触发器和其执行状态的信息。只要创建或删除一个触发器时,这些视图就会更新。源程序代码存储在数据字典视图,user_triggers,中。,删除触发器,DROP TRIGGER,triggername,触发器与数据字典,与过程和包不同的是,触发器可以被禁止使用。当触发器被禁用时,它仍将存储在数据字典中,但永远不会被激发。,ALTER TRIGGER,triggername,DISABLE|ENABLE,与包和子程序一样,触发器编译后的伪代码同源代码一起存储在数据字典中。,变异表,系统对触发器将要访问的表和列有一些限制,变异表是当前被,DML,语句修改的表。对于触发器,变异表就是触发器为之定义的表;由于,DELETE CASCADE,引用完整性约束而可能需要更新的表也是变异表。,约束表是对于引用完整性约束而需要从中读取数据的表。,触发器体中,SQL,语句限制,不能读取或修改任何触发语句的变异表,这也包括触发表本身。,不能读取或修改触发表的约束表中的主关键字、惟一关键字或外部关键字的列。,除此之外的其他列可以修改。,上述限制适用于所有的行级别触发器,只有当因为,DELETE CASCADE,操作而激发语句触发器时,它们才适用于语句触发器。,变异表错误的解决,我们不能在行级别触发器中对变异表进行查询,只能在语句级别触发器使用查询语句。有时可以为了需要,创建两个触发器,一个行级别的,一个语句级别的触发器来完成一定功能。,本章小结,数据库触发器是根据一个事件执行的,PL/SQL,语句块。数据库触发器有三种类型:,DML,触发器、,instead-of,触发器和系统触发器。,CREATE TRIGGER,语句包括执行时间选项(之前或之后),并且可以标识为行级别和语句级别。,行级别触发器对于,DML,事件影响的每一行激发。语句级别触发器只对,DML,事件触发一次,而不管,DML,影响了多少行。,CREATE TRIGGER,语句包括一个可选的,WHEN,子句,它可以检查一个条件,决定是否应该执行触发器。,相关性标识符,:OLD,和,:NEW,允许引用,DML,操作的原始行值和新行值。,触发器谓词,INSERTING,、,UPDATING,和,DELETING,允许在一个触发器中对于不同事件执行不同的,PL/SQL,代码。,本章小结,Instead-of,触发器基于一个视图,并允许通过视图执行,DML,操作。,系统触发器是在,DDL,语句和系统事件上触发的。,如果,DML,语句触发了一个触发器,并且这个触发器尝试引用该,DML,事件所处理的那个表,则将引发一个错误。,ALTER TRIGGER,语句允许编译器禁用或启用触发器。,想要从系统中删除一个触发器,可以使用,DROP TRIGGER,语句。,USER_TRIGGERS,数据字典视图包含了所有触发器声明信息以及源代码。,
展开阅读全文