[包(Package)的设计与开发]
一、什么是包?
把一些相关的存储过程、函数、变量、光标、例外等组合在一起形成的对象叫包。包由包的说明部分及包体两部分组成。定义在包说明部分的是公共元素,定义在包体的部分是私有元素。
二、使用包的优点:
1、规范化程序设计
2、方便过程及函数的组织
3、便于管理:包的授权只需一次完成
4、优化系统性能:整个包作为一个整体一次调入内存。
三、包的开发步骤:
1、创建包的说明部分:Create package
2、创建包体部分:Create package body
3、在SQL*Plus中运行创建包
4、在存储过程、其它应用中调用。
在SQL*Plus中调用方法:SQL> exec 包名.过程名;
在存储过程、函数、其它应用中调用方法:包名.过程名;
四、创建包的语法:
1、创建包(说明部分):请参考PowerPoint教程:存储过程1.ppt[Page10]
2、创建包体(Create Package Body): 请参考PowerPoint教程:存储过程1.ppt[Page11]
3、例:请参考PowerPoint教程:存储过程1.ppt[Page12、13、14、15]
五、包的删除:
SQL> drop package 包名;
SQL> drop package body 包名;
查询包源代码:
SQL> select text from user_source where name = '包名'; // 包名大写。
[数据库触发器(Triggers)设计与开发]
一、 什么是触发器?
数据库触发器是一个存储的PL/SQL程序块,它与一个基表联系,当在表上执行特定的数据库维护(插入、删除、更新这三种操作)时,隐含地执行一个PL/SQL程序块。
二、触发器的作用:
。防止非法的数据库操纵、维护数据库安全
。对数据库的操作进行审计,存储历史数据
。完成数据库初始化处理
。控制数据库的数据完整性
。进行相关数据的修改
。完成数据复制
。自动完成数据库统计计算
。限制数据库操作的时间、权限等,控制实体的安全性
三、触发器的组成:
1、触发时间:触发器事件的时间次序(before, afer)[2]
2、触发事件:什么SQL语句会引起触发器触发(Insert, delete, update)[3]
3、触发子体:触发器触发时要执行的操作(一个完整的PL/SQL程序)
4、触发类型:触发器被执行的次数(语句级、行级)[2] //语句级只执行一次,行级会执行多次。
[*]一个表上最多可以创建12个不同类型的触发器:3*2*2 = 12
四、创建触发器注意事项:
1、在触发器中可以调用存储过程、包;在存储过程中不得调用触发器。
2、在触发器中不得使用commit, rollback, savepoint语句。
3、在触发器中不得间接调用含有commit, rollback, savepoint的语句的存储过程及函数。
五、创建语句级触发器:
语句级触发器: 请参考PowerPoint教程:存储过程1.ppt[Page19] 该触发器在数据库操作时只执行一次。
说明:
。update中的of是可选项,用于指定语句要修改的列
。要创建的触发器已经存在时,使用replace选项
//例1:before型触发器:
Create or replace trigger DelEmp
before delete on emp
Begin
if (To_Char(sysdate,'dy') in ('星期六','星期日') or
To_number(To_Char(sysdate,'hh24')) not between 8 and 18)
then dbms_output.put_line('现在是非工作时间,请退出!!!');
end if;
End;
[触发器数据字典]
SQL> select table_owner, table_name,trigger_body from user_triggers where trigger_name='DELEMP';
//例2:After型触发器:
Create or replace trigger InsertEmp
after insert on emp // 如果是before,就会比after的结果少一名。
Declare
v_empcount number(7);
Begin
select count(*) into v_empcount from emp;
dbms_output.put_line('目前员工总数已达到:'|| v_empcount|| '名。');
End;
//例3:多个触发条件
Create or replace trigger ChangeEmp
before delete or insert or update on emp
Begin
if (To_Char(sysdate,'dy') in ('星期六','星期日') or
To_number(To_Char(sysdate,'hh24')) not between 8 and 18)
then dbms_output.put_line('现在是非工作时间,请不要修改数据!!!');
end if;
End;
// 更完善的写法:
Create or replace trigger ChangeEmp
before delete or insert or update on emp
Begin
if (DELETING and (To_Char(sysdate,'dy') in ('星期六','星期日') or
To_number(To_Char(sysdate,'hh24')) not between 8 and 18))
then dbms_output.put_line('现在是非工作时间,不要删除数据!');
elsif (UPDATING and (To_Char(sysdate,'dy') in ('星期六','星期日') or
To_number(To_Char(sysdate,'hh24')) not between 8 and 18))
then dbms_output.put_line('现在是非工作时间,不要更新数据!');
elsif (INSERTING and (To_Char(sysdate,'dy') in ('星期六','星期日') or
To_number(To_Char(sysdate,'hh24')) not between 8 and 18))
then dbms_output.put_line('现在是非工作时间,不要插入数据!');
end if;
End;
六、创建行级触发器:
等级触发器:增加选项for each row, 使触发器在每一行上触发。
1、创建行级触发器注意事项:
(1) 在行级触发器中,在列名前增加old表示该列修改前值,增加new表示该列修改后值。
(2) 在PL/SQL中引用时,前边增加冒号。
[例4: 行级触发器] //必须是对所有的行进行操作才行。
Create or Replace trigger UpdateEmp
Before update on emp
for each row
Begin
dbms_output.put_line(:old.sal||'--------->'||:new.sal);
End;
[例5:保存历史数据,这种使用方法很重要,用来保存关键表的历史数据]
CReate or Replace trigger ChangeEmp
Before update or delete on emp
for each row
Begin
Insert into oldemp(empno, ename,job,hiredate,sal)
values(:old.empno,:old.ename,:old.job,sysdate,:old.sal);
End;
SQL> create table oldemp
as select empno, ename,job,hiredate,sal from emp where 1>2;
[例6:修改外键]
Create or Replace trigger UpdateDept
after update on dept
for each row
Begin
update emp
set emp.deptno = :new.deptno
where emp.deptno = :old.deptno;
End;
[例7:删除外键、删除相关数据]
Create or Replace trigger DeleteDept
before delete on dept
for each row
Begin
delete from emp where deptno = :old.empno;
End;
七、触发器管理
1、使触发器失效:
SQL> alter trigger 触发器名称 disable; // 失效
SQL> Alter Trigger 触发器名称 enable; // 生效
SQL> Alter table 表名 DISABLE all triggers; // 一个表上的所有触发器失效
SQL> Alter table 表名 ENABLE all triggers; // 使一个表上的所有触发器生效
SQL> Drop Trigger 触发器名; // 删除触发器;