Presentation is loading. Please wait.

Presentation is loading. Please wait.

第四章:触发器   触发器类似于过程、函数,因为它们都是拥有说明部分、语句执行部分和异常处理部分的有名的PL/SQL块。与包类似,触发器必须存储在数据库中,并且不能被块进行本地化说明。但是,对于过程而言,可以从另一个块中通过过程调用显式地执行一个过程,同时在调用时可以传递参数。对于触发器而言,当触发事件发生时就会显式地执行该触发器,并且触发器不接受参数。

Similar presentations


Presentation on theme: "第四章:触发器   触发器类似于过程、函数,因为它们都是拥有说明部分、语句执行部分和异常处理部分的有名的PL/SQL块。与包类似,触发器必须存储在数据库中,并且不能被块进行本地化说明。但是,对于过程而言,可以从另一个块中通过过程调用显式地执行一个过程,同时在调用时可以传递参数。对于触发器而言,当触发事件发生时就会显式地执行该触发器,并且触发器不接受参数。"— Presentation transcript:

1 第四章:触发器 触发器类似于过程、函数,因为它们都是拥有说明部分、语句执行部分和异常处理部分的有名的PL/SQL块。与包类似,触发器必须存储在数据库中,并且不能被块进行本地化说明。但是,对于过程而言,可以从另一个块中通过过程调用显式地执行一个过程,同时在调用时可以传递参数。对于触发器而言,当触发事件发生时就会显式地执行该触发器,并且触发器不接受参数。

2 触发事件是在数据库表上执行的DML(INSERT、UPDATE、DELETE)操作。使用触发器,可以做许多事情,包括:
● 维护不可能在表创建时通过说明性约束进行的复杂 的完整性约束限制。 ● 通过记录所进行的修改以及谁进行了修改来审计表 中的信息。 ●当表被修改的时候,自动给需要执行操作的程序发信 号。

3 1.触发器概念及组成 制作一个数据库触发器,目的是在某个表上执行特定的数据维护操作时,隐含地执行一个PL/SQL块。

4

5 例子:制作一个数据库触发器。记录下那些超过其工种工
资范围的工资值(但不禁止这种操作) CREATE TRIGGER check_sal BEFORE INSERT OR UPDATE OF sal,job ON emp FOR EACH ROW WHEN(new.job<> ‘PRESIDENT’) DECLAER v_minsal sal_guide.minsal%TYPE; v_maxsal sal_guide.maxsal%TYPE; e_sal_out_of_range EXCEPTION;

6 BEGIN SELECT minsal,maxsal INTO v_minsal,v_maxsal FROM sal_guide WHERE job = :new. job; IF :new.sal<v_minsal OR :new:sal>v_maxsal THEN RAISE e_sal_out_of_range; END IF; EXCEPTION WHEN e_sal_out_of_range THEN INSERT INTO audit_message(line_nr,line) VALUES(l,‘Salary’|| TO_CHAR(:new.sal)|| ‘is out of range for employee’||TO_CHAR(:new.empno)); END;

7 ★ 关联触发器 把一个数据库触发器的动作与另一个触发器联系起来,使之触发这另一个触发器。

8 例子——制作相关联的触发器。在一个全局变量中统计
审计信息的总数 CREATE TRIGGER count_audit_message BEFORE INSERT ON audit_message BEGIN emp_package.v_total_audit:=emp_package.v_total_audit+1; END; 注释: ·参数MAXOPENCURSORS限制在一个数据库中可用 的关联触发器的个数,其缺省值为32。

9

10 ★ 写触发器的源代码之前,先确定好其触发时间、触发事件及触发器的类型。 内容 描述 可能值 触发时间 与触发事件的时间次序 ● BEFORE
内容 描述 可能值 触发时间 与触发事件的时间次序 ● BEFORE ● AFTER  触发事件 触发触发器的数据操作 ● INSERT 事件类型 ● UPDATE ● DELETE  触发器类型 触发器体被执行的次数 ● Statement ● ROW  触发器体 该触发器将要执行的动作 完整的 PL/ SQL块

11 通过对触发器各部分的不同组合,对同一表最多可以创建12个触发器。

12 ★ 数据库触发器与存储过程之间的关键性区别。
数据库触发器 存储过程 __________________________________________________当某类数据操纵发生 从一个应用或过程中显式地调 时隐式地调用 用 在触发器体内禁止使用 在过程体内可以使用所有 PL/COMMIT,BOLLBACK, SQL块 中能使用的 SQL语句 SAVEPOINT语句

13 注释: ● 不但禁止在触发器内用 COMMIT,ROLLBACK和SAVEPOINT语句,而且禁止触发器直接或间接地调用那些含有COMMIT,ROLLBACK和SAVEPOINT语句的存储过程。

14 ★ 数据库触发器和Forms触发器的区别 数据库触发器 Forms触发器 可被任何数据库工具或 只能在特定的Forms应用中执行 应用调用、执行 常常被一个 SQL数据 触发事件可能是从一个域到另一个 操纵语句触发 域、或按下了一个功能键、或许多其 它的事件或动作 分为语句级触发器和 不为分语句级触发器和行级触发器 行级触发器 发生错误时,返回被触 发生错误时,锁住游标,并回退整个 发的语句 事务 独立于Forms触发器触发 独立于数据库触发器触发

15 ★ 行级触发器与语句级触发器的区别 根据进行一个操作时触发器的触发次数,来决定是创建一个语句级触发器,还是创建一个行级触发器。 ● 注意当某操作只影响到表中的一行数据时,语句级触发器与行级触发器的效果相同。

16 例子:下面的语句对语句级触发器和行级触发器效果一样
SQL> INSERT INTO DEPT(deptno,dname) VALUES(50,‘EDUCATION’); SQL> UPnATE DEPT SET LOC=‘MAUI’ WHERE DEPTNO=50; SQL> DELETE FROM DEPT WHERE DEPTNO=50;

17

18 ●当触发事件影响数据库的多行时,语句级触发器只触发一次,而行级触发器则每一行被触发一次。

19 例子----下列语句的行级触发器与语句级触发器效果不同
SQL>INSERT INTO EMP(empno,ename) 2 SELECT empno,ename 3 FROM EMP_BACKUP; SQL> UPDATE DEPT 2 SET SAL= SAL*1.1 3 WHERE DEPTNO=10; SQL> DELETE FROM EMP 2 WHERE DEPTNO=10;

20 注释: ● 在一个预编译应用中进行数组处理时,行级触发器与语句级触发器的结果不同。

21 2.创建触发器 ⑴ 开发触发器的步骤 ●用系统编辑器或字处理软件写一个含有 CREATE TRIGGER语句的脚本文件。
⑴ 开发触发器的步骤 ●用系统编辑器或字处理软件写一个含有 CREATE TRIGGER语句的脚本文件。 ●在写 CREATE TRIGGER语句时,充分考虑运行时出 错的处理。 ●在 SQL*Plus或 SVRMGR中运行脚本文件,将触发器的 源代码编译成编译代码p_code,并把源代码存储到数据 库中。编译代码p_code不存储在数据库中。 ●调试编译错误。 ●在 ORACLE环境中测试开发的触发器(用INSERT、 UPDATE、DELETE语句对表进行操作)。 ●在运行期间调试触发器的逻辑错误。

22 ⑵ 语句级触发器 用 CREATE TRIGGBR语句创建一个语句级触发器,该触发器在一个数据操作语句发生时只触发一次。
用 CREATE TRIGGBR语句创建一个语句级触发器,该触发器在一个数据操作语句发生时只触发一次。 语法——创建一个语句级触发器 CREATE [OR REPLACE ] TRIGGER trigger_name {BEFORE|AFTER} event1 [OR event2...] ON table_name PL/SQL block

23 其中: trigger name 触发器名 timing 指明触发事件触发的时间顺序: ● BEFORE ● AFTER event 指明触发事件的数据操纵类型 ● INSERT ● UPDATE ● DELETE table name 标明与该触发器相关联的表名 pl/sql block 触发器体,指明该触发器将执行的操

24 注释: ● 当触发器已经存在时,用 REPLACE选项。 ● 用 OF关键字指明 UPDATE事件修改的特定的列。
● 当触发器已经存在时,用 REPLACE选项。 ● 用 OF关键字指明 UPDATE事件修改的特定的列。 ● PL/SQL块以 DBCLARE或BEGIN开头,以 END结 束。

25 例子1——创建一个 BEFORE型语句级触发器。限制一周内往 EMP表插入数据的时间
CREATE OR REPLACE TRIGGER secure_emp BEFORE INSERT ON emp DECLARE v_dummy VARCHAR2(l); BEGIN IF(TO_CHAR(sysdate,‘DY’) IN(‘SAT’,‘SUN’)) OR(TO_CHAR(sysdate,‘HH24’) NOT BETWEEN 8 AND 18) THEN RAISE_APPLICATION_ERROR(-20500, ‘YOU may only insert into EMP during normal hours.’); END IF; END;

26 例子2:创建一个 AFTER型语句级触发器。以在事件完成后对触发事件进行审计,或者执行计算。
假定用户有一个自定义的审计表,其中包含所有用户和他们进行数据操纵操作的计数信息。当一个用户对EMP表中的薪水进行修改时,利用审计表来保证某用户薪水的变化值不超过其允许值。

27 CREATE TRIGGER check_sal_count AFTER UPDATE OF sal ON emp DECLARE
v_sal_changes NUMBER; v_max_changes NUMBER; BEGIN SELECT upd, max_upd INTO v_sal_changes,v_max_changes FROM audit_table

28 注释: WHERE user_name=user AND table_name=‘EMP’ AND column_name=‘SAL’;
IF v_sal_changes>v_max_sal_changes THEN RAISE_APPLICATION_ERROR(-20501, ‘YOU may only make a maximum of’|| TO_CHAR(v_max_changes)||‘to the SAL olumn.’); END IF; END; 注释: ● 如果某触发器没必要在触发事件发生后触发,创建 BEFORE型语句级触发器。

29 例子:创建一个包含多个触发事件的触发器。在触发器体中使用条件语句,指明 INSERTING,UPDATING及 DELETING,从而把多种触发事件组成一个触发器。
对前面的例子进行扩展,使其不但限制某周内插入数据的时间,还限制进行数据修改和删除的时间。

30 CREATE TRIGGER secure_emp
BEFORE DELETE OR INSERT OR UPDATE ON emp DECIARE v_dummy VARCHAR2(1); BEGIN IF (TO_CHAR(sysdate,‘DY’ IN (‘SAT’,‘SHN’)) OR(TO_NUMBER(sysdate,‘HH24’) NOT BETWEEN 8 AND18) THEN IF DELETING THEN RAISE_APPLICATION_ERROR(一20502, ‘You may only delete from EMP during normal hours.’) ; ELSIF INSERTING THEN RAISE_APPLICATION_ERROR(一20500, ‘You may only insert into EMP during mormal hours.’) ;

31 ELSIF UPDATING(‘SAL’) THEN
RAISE_APPLICATION_ERROR(一20503, ‘You may only update SAL column during normal hours.’) ; ELSE RAISE_APPLICATION_ERROR(一20504, ‘You may only update EMP table during normal hours.’) ; END IF; END;

32 ⑶ 行级触发器 通过在 CREATE TRIGGER语句中指定 FOR EACH ROW子句创建一个行级触发器,使其在受到触发事件影响的每一行上都被触发。 ★ 语法:创建一个行级触发器 CREATE [OR REPLACE] TRIGGER trigger_name {BEFORE|AFTER} trigger_event1 [OR trigger_event2...] ON table_name [FOR EACH ROW [WHEN restricting_condition]] PL/SQL block; 其中: restricting condition为指定的条件,以确定触发器体是否被执行。

33 例子:创建一个行级触发器。记录下每个用户对数据库的表进行数据操纵的次数
CREATE TRIGGER audit_emp AFTER DELETE OR INSERT OR UPDATE ON emo FOR EACH ROW BEGIN IF DELETINC THEN UPDATE audit_table SET del= del+l WHERE user_name=user AND table_name=‘EMP’ AND colun_name IS NULL;

34 ELSIF INSERTING THEN UPDATE audit_table SET ins=ins+l WHERE user_name=user AND table_name=‘EMP’ AND column_name IS NULL; ELSIF UPDATING(sal) THEN SET upd=upd+l WHERE user_name=user . AND column name=‘SAL’;

35 注释: EISE UPDATE audit_table SET upd=upd+1 WHERE user_name= user
AND table_name=‘EMP’ AND column_name IS NULL; END IF; END; 注释: ● 如果一个触发器不必在触发事件前触发,请创建 AFTER型触发器(不要创建 BEFORE型)

36 ★ 行级触发器的标识符 在行级触发器中,在列名前加上 OLD标识符标识该列变化前的值,加上 NEW标识符标识变化后的值。 数据操作 旧值 新值 Insert NULL 插入的值 Update 修改前的值 修改后的值 Delete 删除前的值 NULL

37 注释: ● 在 BEFORE型行级触发器和 AFTER型行级触发器 中使用这些标识符。 ● 在语句级触发器中不要使用这些标识符。
● 在 BEFORE型行级触发器和 AFTER型行级触发器 中使用这些标识符。 ● 在语句级触发器中不要使用这些标识符。 ●在SQL语句或 PL/SQL语句中,在这些标识符前加 冒号(:)来引用它们。

38 例子:在行级触发器中获取某列的新值和旧值。为 EMP表中的所有数据保留一个历史档案(审计)
CREATE TRIGGER audit_emp_values AFTER DELETE OR INSERT OR UPDATE ON emp FOR EACH ROW BEGIN INSERT INTO audit_emp_values(user_name,timestamp, empno,old_ename,new_ename,old_job,new_job, old_mgr, new_mgr, old_sal,new_sal) VALUES(USER,SYSDATE,:old.empno,:old.ename, : new.ename,:old.jOb,:new.job,:old.mgr, :new.mgr,: old.sal,:new. sal); END;

39 详细的用户审计表 用 WHEN子句来保证,当某些行满足一定条件时,在该行上行级触发器才被触发。

40 注释: 例子:在行级触发器限制其触发。自动计算销售员的奖金 CREATE TRIGGER derive_comm
CREATE TRIGGER derive_comm BEFORE INSERT OR UPDATE OF sal ON emp FOR EACH ROW WHEN (new.job=‘SALESMAN’) BEGIN :new.comm := :old. comm * (:new. sal/ :old. sal); END; 注释: ● 在 WHEN子句中,标识符前不加冒号(:) ● 在语句级触发器中不要使用 WHEN子句。

41 ⑷ 语句级和行级触发器的作用 根据不同的情况创建语句级触发器和行级触发器。 ★ 利用语句级触发器实现下列例程 ● 防止非法的数据操纵
根据不同的情况创建语句级触发器和行级触发器。 ★ 利用语句级触发器实现下列例程 ● 防止非法的数据操纵 ● 审计数据操作 ● 控制数据操作的安全性 ● 初始化和重新给全局变量及标志赋值

42 ★ 利用行级触发器实现下列例程 ● 防止行上的非法数据 ● 审计受数据操纵影响的行的信息及其值的信息 ● 控制数据完整性及参考完整性 ● 用全局变量和标志控制数据操作 ● 复制表 ● 透明地计算获得的值 ● 修改数据并隐式地执行函数

43 ⑸ INSTEAD OF 触发器 INSTEAD OF 触发器可用来操纵对视图的插入、修改、删除。当一个视图是根据几个表创建的时候,INSTEAD OF 触发器就特别有用。INSTEAD OF 触发器的工作方式与行级、语句级触发器是类似的。在下面的代码中,在EMPLOYEE_NAMES视图上创建了两个触发器。 第一个触发器将直接插入雇员表。它还将INSERT 语句中的雇员标识的值废掉。而在为了生成雇员标识号而定义的序列生成器中插入下一个值。

44 Create or replace trigger employee_names_trigger
Instead of insert on employee_names Begin Insert into employee values (employee_sequence.nextval,:new.f_name,:new.l_name ,null,null,null,null); end; /

45 第二个触发器生成一条用户定义的报错语句,它责备用户企图通过这个视图删除雇员。虽然经常允许对视图处理这类操作,但是能产生一条比通常的‘ORA-01031:没有足够权限’说明得更清楚的报错消息总是件好事。
Create or replace trigger employee_names_trigger_delete Instead of delete on employee_names Begin Raise_application_error(-20002,’you may not delete Employee through this views!’); End; /

46 3.触发器的管理 管理触发器的命令与管理过程的命令相似。 任务 命令
任务 命令 ___________________________________________________ 创建一个新的触发器 CREATE TRIGGER 修改一个已有的触发器 CREATE OR REPLACE TRIGGER 删除触发器 DROP TRIGGER 与过程不同的是,当一个触发器不再适宜被触发时,可以使其处于无效状态。

47 注释: 语法——使一个数据库触发器无效 ALTER TRIGGER—— trigger name—DISABLE
ALTER TRIGGER—— trigger name—DISABLE 语法:使一个数据库触发器重新变为有效 ALTER TRIGGER——trigger name—ENABLE 注释: ● 当触发器刚创建时,它被自动置为有效。 ● 为了改善性能,以及在大量装载数据时(例如使用 SQL* Loader)避 免进行数据的完整性校验,可以使 数据库触发器暂时无效。 ●当发生网络连接故障、磁盘损坏,数据文件脱机或 表空间脱机,从而导致触发器中涉及到的实体不能 再被访问时,应使触发器失效。

48 ★ 存储触发器和存储一个过程之间的一个重要区别
存储一个触发器 ● 在一个文本文件中写入 CREATE TRIGGER语句。 ● 运行该文本文件,以运行 CREATE TRIGGER语句。 · 如果触发器编译成功,则数据库只将其源代码存入 库中,编译代码不进行存储。 · 当发生编译错误时,ORACLE以交互方式将触发器 的语法错误通知用户,但这些错误信息不进行存储。 ● 当触发器触发时,必须首先重新编译。

49 存储一个过程 ● 写一个含 CREATE PROCEDURE语句的文本文 件。 ● 运行该文件。 · 如果过程编译成功,其源代码和编译代码都 被存人数据库中。 · 如果出现编译错误,则这些语法错误信息将 被存人数据字典中。 ● 当运行一个过程时,通常不需要对其重新编译。 ● 如果需要,用手动方式重新编译该过程。

50 ★ 管理触发器的命令与管理过程的命令稍有差别。

51 注释: ● 虽然触发器中可以引用另外的数据库实体,但它们之 间并没有依赖关系,因为触发器在每次触发前都要重新 编译。
● 虽然触发器中可以引用另外的数据库实体,但它们之 间并没有依赖关系,因为触发器在每次触发前都要重新 编译。 ● 无法手工编译触发器。

52 查看数据字典中 USER_TRIGGERS视图,可以获取合法触发器的源代码。下面是该视图的结构。
列 列描述 NAME 触发器名 TYPE 触发时间(BEFORE或AFTER)以及触发类型 (语句级或行级) TRIGGERING_ 触发事件的语句类型STATEMENT (INSERT、 UPDATE或 DELETE) TABLE_OWNER 与该触发器相关联的表的拥有用户名

53 注释: WHEN 限制触发条件 ENABLED 触发器的状态(ENABLED或 DISABLED)
ENABLED 触发器的状态(ENABLED或 DISABLED) TRIGGER_BODY 完整的 PL/SQL块文本 注释: ● 用户还可以查看数据字典中的 DBA_TRIGGERS视图和 ALL_TRIGGERS视图,你会发现这两个视图除了上面 的列外,还有一个新列 OWNER,标明了触发器的拥 有者。

54 用 SELECT查看触发器的文档信息。 例子:查看 DERIVE_COMM触发器的文档。 TRIGGER_BODY
    例子:查看 DERIVE_COMM触发器的文档。 SSQL> SELECT trigger_body FROM user_triggers WHERE name=‘DERIVE_COMM’; TRIGGER_BODY BEGIN :new.comm := :old. Comm*(:new.sal/:old. sal); END;

55 注释: ★ 测试触发器的实例 用多种事件分别对触发器进行测试,以确保触发器的正确运行 ● 用各种触发事件和一个非触发事件对触发器进行测试
用多种事件分别对触发器进行测试,以确保触发器的正确运行 ● 用各种触发事件和一个非触发事件对触发器进行测试 ● 用满足 WHEN条件的实例进行测试。 ● 用直接的数据操作以及从过程中的间接数据操作进行测试。 ● 观察触发器依赖于其它触发器时的结果。 ● 观察当别的触发器依赖于该触发器时的结果。 注释: ● 利用 DBMS_OUTPUT包进行调试

56 例:制作一个 SQL*Plus批文件,测试 DERIVE_COMM触发器。
ACCEPT p_empno PROMPT ‘please enter the new employee number:’ ACCEPT p_ename PROMPT ‘Please enter the new employee name:’ ACCEPT p_job PROMPT ‘Please enter the new employee job :’ ACCEPT p_mgr PROMPT ‘PIease enter the new manager number:’ ACCEPT p_hiredate PROMPT ‘PIease enter the new hiredate:’ ACCEPT p_sal PROMPT ‘please enter the new salary:’ ACCEPT p_deptno PROMPT ‘Please enter the new department INSERT INTO emp(empno,ename,job ,mgr,hiredate,sal,deptno) VALUES(&p_empno,‘&p_ename’,‘&p_job’,&p_mgr, ‘&p_hiredate’, &p_sal,&p_deptno);

57 ACCEPT p_empno PROMPT ‘please enter the old employee number:’
ACCEPT p_ename PROMPT ‘PIease enter the new employee name:’ ACCEPT p_jOb PROMPT ‘Please enter the new employee job:’ ACCEP7 p_mgr PROMPT ‘Please enter the new manager number:’ ACCEPT p_hiredate PROMPT ‘Please enter the new hiredate:’ ACCEPT p_sal PROMPT ‘please enter the new salary:’ ACCEPT p_deptno PROMPT ‘Please enter the new department number:’ UPDATE EMP SET ename‘&p_empno’, job = ‘&p_job ’, mgr=&p_mgr, hiredate=‘&p_hiredate’, sal=&p_sal, deptno= &p_deptno WHERE empno=&p_empno;

58 4.在触发器中进行的数据操作 ⑴ 修改没有关联的表的数据

59

60 例子:修改一个与触发器没有相联的表。 为 EMP表中的所有数据做一个历史记录 CREATE TRIGGER audit_emp_values AFTER DELETE OR INSERT OR UPDATE ON emp FOR EACH ROW BEGIN INSERT INTO emp_audit(user_name, timestamp, empno,old_ename,new_ename,old_job,new_job, old_mgr,new_mgr,old_sal,new_sal)

61 VALUES(USER,SYSDATE,:Old.empno,:old.ename,
:new.ename,:Old.jOb,:new.job,:old.mgr, :new.mgr,:old.sal,: new. sal);. END;

62 WHERE ename=:‘SCOTT’;
SQL> UPDATE emp SET job=‘PRESIDENT’ WHERE ename=:‘SCOTT’; 注释: ● 对与触发器没有相联的表的修改没有限制。

63 ⑵ 修改被触发表的不同列数据

64 例子:修改被触发的表。自动计算销售人员的奖金。
CREATE TRIGGER derive_comm BEFORE INSERT OR UPDATE OF sal ON emp FOR EACH ROW WHEN (new.job=‘SALESMAN’) BEGIN :new.comm :=:old.comm*(:new.sal/:old.sa1); END; SQL> UPDATE KMP SET sal=1500 WHERE ename=‘MARTIN’;

65 注释: ● 只有在 BEFORE型的行级触发器中,允许 NEW标识符 出现在赋值语句的左边。
● 只有在 BEFORE型的行级触发器中,允许 NEW标识符 出现在赋值语句的左边。 ● 在 AFTER型的行级触发器中和语句级触发手中,NEW 标识符都不允许出现在赋值语句的左边。 ● 单独的列名,或者加上了 OLD标识符的列名,绝对禁 止出现在赋值语句的左边。

66 ⑶ 修改被触发表的同一列数据 例子——修改被触发表的同一列数据。给公司雇员加薪,最大增加量为10%

67

68 CREATE TRIGGER derive_sal
BEFORE INSERT OR UPDATE OF sal ON emo FOR EACH ROW BEGIN :new.sal:=least(:new.sal, :old.sal* 1.1); END; SQL> UPDATE EMP SET sal=1500 WHERE ename=‘MARTIN’;

69 ⑷ 修改有约束关系的关联表中的非主键列

70 例子——修改一个有约束关系的相关联表的非主键列数据。将部门名附到雇员名之后,送入 ENAME列。
CREATE TRIGGER append_dname AFTER INSERT OR UPDATE OF dname ON dept FOR EACH ROW BEGIN UPDATE emp SET emp.ename=emp.ename||‘-’||:new.dname WHERE emp.deptno= :new.deptno; END;

71 SQL> UPDATE DEPT SET dname=‘FINANCES’ WHERE dname=‘ACCOUNTING’; 注释: ● 关联表是指通过参考完整性的约束声明,由被触发基表间接或直接参考的基表。

72 ⑸ 不允许修改有约束关系的关联表中的主键列

73 例子——一个修改关联表主键列的失败的实例。
当父表(DEPT表)中的 DEPTNO列发生变化时,导致子表(EMP表)的相关行的数据发生变动。(该例子将导致一个运行错)

74

75 ⑹ 读取一个没有变化的表的数据

76 例子——从一个没有变化的表中读取数据 强行在雇员的薪水和其工作之间制作一个复杂的完整性限制,使其薪水不能超出其工作所允许的薪水范围。

77

78

79 ⑺ 不允许从一个变化的表中读取数据 例子——一个失败的从变化表中读取数据的实例 把薪水限制在目前的最低薪水与最高薪水之间。(下面的例子将出现一个运行错)

80

81 注释: ● 变化表是指直接或间接地受触发事件影响的表。 ● 与触发器发生联结的表本身是一个变化表。 ● 通过 DELETE CASCADE完整性约束与被触发表产生联系的表是变化表

82

83 ★ 在触发器中进行数据操作总结 利用触发器读取或写入数据时,必须满足两个原则: ● 不要修改相关表的主关键字、外部关键字以及唯一性关键字所在的列。 ● 不要从变化表中读取数据。

84

85 在应用程序中创建数据库触发器,可以大大增强 ORACLE系统的性能,完成一些 ORACLE系统服务不能完成的功能。
5.触发器的应用 在应用程序中创建数据库触发器,可以大大增强 ORACLE系统的性能,完成一些 ORACLE系统服务不能完成的功能。

86

87 ⑴ 安全性 ★ 在系统服务中控制实体的安全性。 在 ORACLE中创建用户和角色,通过用户的标识完成对表中数据进行操作的安全性管理。
● 只有基于用户联结到数据库时提供的用户名的权限 ● 确定对表、视图、同义词、序列生成器的访问。 ● 确定查询、数据维护及数据定义权限。

88 例子——在系统服务进程中进行安全性控制。
限制用户对 EMP表的访问,使某些用户拥有访问它的权限。 SQL> GRANT CLERK TO JOE; SQL> GRANT SELECT,INSERT,UPDATE,DELETE ON EMP TO CLERK;

89 ★ 用触发器控制实体的安全性 ● 将权限基于各种数据库的值,如时间、星期等。 ● 只决定访问表的权限。 ● 只决定数据操纵权限。 例子——在一个触发器中控制数据的安全性。限制只允许在某周的特定时间内进行数据操作。

90

91 ⑵ 审计 ★ 通过系统服务进行审计 ● 可审计查询,数据操纵及数据定义语句。 ● 把审计情况写入集中的审计表中。
★ 通过系统服务进行审计 ● 可审计查询,数据操纵及数据定义语句。 ● 把审计情况写入集中的审计表中。 ● 在每次启动时或每次访问时在审计表中增加新 的一行。 ● 捕获成功和失败的操作。 ● 动态地设置(ENABLE和 DISABLE)。

92 例子——利用系统服务进行审计。审计EMP表上的所有数据操作。
SQL> AUDIT INSERT,UPDATE,DELETE ON emp BY ACCESS WHENEVER SUCCESSFUL;

93 ● 在每次启动或访问时往审计表中增加新的行。 ● 只审计成功的操作。 ● 动态设置审计标志。
★ 在触发器中进行审计 ● 只审计数据操纵语句。 ● 将审计情况写入用户的审计表。 ● 在每次启动或访问时往审计表中增加新的行。 ● 只审计成功的操作。 ● 动态设置审计标志。 例子:——在触发器中进行审计。审计EMP表上所有成功的数据操作的数据值。

94 AFTER DELETE OR INSERT OR UPDATE ON emp FOR EACH ROW BEGIN
CREATE TRIGGEB audit_emp_values AFTER DELETE OR INSERT OR UPDATE ON emp FOR EACH ROW BEGIN IF audit_emp_package.v_reason IS NULL THEN RAISE_APPLICATION_ERROR(-20059,‘Specify a reason for the data operation with the procedure SET_REASON before proceeding.’) ; ELSE INSERT INTO audit_emp_values(user_name,timestamp,empno, old_ename,new_ename,old_job,new_job,old_mgr, new_mgr,old_sal,new_sal, comments) VALUES(user, sysdate, :old.empno,:old.ename, :new.ename ,:old.jOb, :new.job, :old.mgr, :new.mgr,:old.sal,:new.sal, audit_package.reason); END IF; END;

95 AFTER INSERT OR UPDATE OR DELETE ON emp BEGIN
CREATE TRIGGER cleanup_audit_emp AFTER INSERT OR UPDATE OR DELETE ON emp BEGIN audit_package. Reason:= NULL; END;

96 ⑶ 数据完整性 ★ 利用系统服务保证数据的完整性 ● 保证标准的数据完整性的原则:不为 NUIL, 不能重复用主关键字和外部关键字。
★ 利用系统服务保证数据的完整性 ● 保证标准的数据完整性的原则:不为 NUIL, 不能重复用主关键字和外部关键字。 ● 提供固定的缺省值。 ● 加强统计限制。 ● 动态设置 ENABLE和 DISABLE。

97 例子——利用系统服务保证数据的完整性管理。保证雇员的薪水不低于$500。
SQL> CREATE TABLE emp ( .... sal NUMBER(7,2) CHECK(sal>=500), );

98 ★ 利用触发器增强数据的完整性 ● 加强非标准的数据完整性检查。 ● 提供可变的缺省值。 ● 提供动态约束。 ● 动态地 ENABLE和 DISABLE。

99 例子—一用触发器实现数据的完整性。确保薪水不能降低,但同时增长幅度一次不能超过10%。
CREATE TRIGGER check_sal BEFORE UPDATE OF saI ON emp FOR EACH ROW WHEN(new.sal<old.sal) OR (new.sal> old.sal*1.1) BEGIN RAISE_APPIICATION_ERROR(-20508, ‘Do not decrease salary nor increase by more than 10%’); END;

100 ⑷ 参考完整性(关联完整性)

101 SQL> CREATE TABLE emp ( ...
例子----增强参考完整性。当删除父表DEPT中的某个部门时,同时删除子表EMP中该部门的职员。 SQL> CREATE TABLE emp ( ... deptno NUMBER(2) REFERENCES DEPT(DEPTNO) ON DELETE CASCADE);

102 利用触发器增强参考完整性

103 例子----用触发器增强参考完整性约束。当DEPT表的DEPTNO发生变化时,EMP表相关行也要跟着进行适当的修改。
CREATE TRIGGER CASCADE_UPDATE AFTER UPDATE OF DEPTNO ON DEPT FOR EACH ROW BEGIN UPDATE EMP SET EMP.DEPTNO=:NEW.DEPTNO WHERE EMP.DEPTNO=:OLD.DEPTNO; END; 注意:本例只有在定义表DEPT和EMP时没有做参考完整性限制时才能正确执行。

104 ⑸ 数据复制 ★ 利用系统的快照功能为表做复制 ● 按用户定义的时间间隔,定期异步地对表进行备份。 ● 把快照建立在多个主表上。
★ 利用系统的快照功能为表做复制 ● 按用户定义的时间间隔,定期异步地对表进行备份。 ● 把快照建立在多个主表上。 ● 只能从快照中读数据,不能进行写操作。 ● 改善在主表上的数据操作性能,当发生网络失败时, 这一点尤其明显。

105 例子——利用快照拷贝表中数据。在旧金山创建一个建立在纽约的远地表上的快照。
CREATE SNAPSHOT emp_copy AS SELECT * FROM 注释: ● 当创建快照时,不要再创建 AFTER型行级触发器,因为快照就是通过内部的 AFTER型行级触发器实现的。

106 ★ 利用触发器复制表 ● 实时,同步地拷贝表中数据。 ● 表的复制通常只针对一个主表。 ● 既可从表的复制中读取数据,也可以往其中写 入数据。 ● 降低主表上的数据操作性能,这种情况在发生 网络失败时尤其突出。

107 例子——为一个表做复制。在纽约,为远地的旧金山制作一个基于本地表 EMP的复制。
CREATE TRIGGER emp_replica BEFORE INSERT OR UPDATE ON emp FOR EACH ROW DECLARE

108 IF :new.flag IS NULL THEN INSERT INTO emp@sf
BEGIN IF INSERTING THEN IF :new.flag IS NULL THEN INSERT INTO VALUES(:newempno,:new.ename,... ‘B’) ; :new.flag= ‘A’; END IF; EISE IF :new.flag= :old.flag THEN UPDATE SET ename=:new.ename ,... flag= :new.flag WHERE empno= :new.empno; IF :old.flag=‘A’ THEN :new.flag=‘B’; :new.flag=‘A’; END;

109 6. 触发器的优点 除了具有存储过程的优点外,数据库触发器还有许多其它的优点: ★ 提高数据的安全性
除了具有存储过程的优点外,数据库触发器还有许多其它的优点: ★ 提高数据的安全性 ● 为数据操作提供了基于值的安全性检验机制 ● 为数据操作提供了基于值的审计 ★ 提高数据的完整性 ● 在数据库一级增强了数据完整性的动态限制。 ● 增强了复杂的参考完整性约束。 ● 确保一些相关的操作隐式地一起进行。


Download ppt "第四章:触发器   触发器类似于过程、函数,因为它们都是拥有说明部分、语句执行部分和异常处理部分的有名的PL/SQL块。与包类似,触发器必须存储在数据库中,并且不能被块进行本地化说明。但是,对于过程而言,可以从另一个块中通过过程调用显式地执行一个过程,同时在调用时可以传递参数。对于触发器而言,当触发事件发生时就会显式地执行该触发器,并且触发器不接受参数。"

Similar presentations


Ads by Google