一、PL/SQL包概述
1. 什么是PL/SQL包:
相关组件的组合:PL/SQL类型、变量,数据结构,和表达式、子程序: 过程和函数
2. 包的组成部分:
由两部分组成:
包头
包体
3. 包的优点
一次读取多个对象进入内存
二、PL/SQL包的组件
包头:公共部分:包内和包外的程序都可以访问
包体:私有部分:包体定义的变量或者程序只能被本包内的程序调用
1. 创建包头
语法:
CREATE [OR REPLACE] PACKAGE package_name IS|AS public type and variable declarations subprogram specifications END [package_name];
OR REPLACE选项删除并且重新创建包
在包头声明的变量初始化值默认为NULL
所有在包头声明的结构,对于所有授予该包权限的用户都是可见的
包声明示例: comm_pkg
CREATE OR REPLACE PACKAGE comm_pkg IS std_comm NUMBER := 0.10; --initialized to 0.10 PROCEDURE reset_comm(new_comm NUMBER); END comm_pkg; / STD_COMM 是一个全局变量,初始为0.10 RESET_COMM 用于重新设置奖金的过程,它在包体中被定义
2. 创建包体
语法:
CREATE [OR REPLACE] PACKAGE BODY package_name IS|AS private type and variable declarations subprogram bodies [BEGIN initialization statements] END [package_name];
OR REPLACE选项删除并且重新重建包体
包体中定义的标识符是私有的,包体之外不可见
所有的私有结构,在引用前必须先声明
公共结构在包体中是可见的
create or replace package comm_pkg is std_comm number := 0.10; procedure reset_comm(new_comm number); end; create or replace package body comm_pkg is function validate(comm number) return boolean is max_comm employees.commission_pct%type; begin select max(commission_pct) into max_comm from employees; return(comm between 0 and max_comm); end validate; procedure reset_comm(new_comm number) is begin if validate(new_comm) then std_comm := new_comm; else raise_application_error(-20210, 'Bad Commission'); end if; end reset_comm; end;
三、调用包中的子程序
在同一个包内调用子程序:
CREATE OR REPLACE PACKAGE BODY comm_pkg IS ... PROCEDURE reset_comm(new_comm NUMBER) IS BEGIN IF validate(new_comm) THEN std_comm := new_comm; ELSE ... END IF; END reset_comm; END comm_pkg;
在sqlplus中调用包中的过程:
SQL> execute comm_pkg.reset_comm(0.15); SQL> set serveroutput on; SQL> ed declare v_std_comm comm_pkg.std_comm%type; begin v_std_comm := comm_pkg.std_comm; dbms_output.put_line(v_std_comm); end; / 结果: SQL> / std_comm:.15 PL/SQL procedure successfully completed
在不同模式下调用包内的过程
SQL> conn hr/hr SQL> grant execute on comm_pkg to scott; conn scott/tiger SQL> execute comm_pkg.reset_comm(0.36); PL/SQL procedure successfully completed SQL> SQL> declare 2 v_std_comm comm_pkg.std_comm%type; 3 begin 4 v_std_comm := comm_pkg.std_comm; 5 dbms_output.put_line('v_std_comm:' || v_std_comm||'std_comm:' || comm_pkg.std_comm); 6 end; 7 / v_std_comm:.36std_comm:.36 PL/SQL procedure successfully completed
注意:千万不要在sql窗口中写入这段话,不然执行过程是在sql中执行,全局变量存在于sql进程中吗,不会存在sql窗口中,所以在sql窗口中访问到的永远都是std_comm的初始值:0.10
四、创建和使用无体包
create or replace package global_consts is mile_2_kilo CONSTANT NUMBER := 1.6093; kilo_2_mile CONSTANT NUMBER := 0.6214; yard_2_meter CONSTANT NUMBER := 0.9144; meter_2_yard CONSTANT NUMBER := 1.0936; end;
无体包内声明的变量时全局变量,包外的子程序或者匿名块都可以使用
在匿名块中使用:
BEGIN DBMS_OUTPUT.PUT_LINE('20 miles = ' || 20 * global_consts.mile_2_kilo || ' km'); END;
在子程序中调用:
CREATE FUNCTION mtr2yrd(m NUMBER) RETURN NUMBER IS BEGIN RETURN(m * global_consts.meter_2_yard); END mtr2yrd; begin DBMS_OUTPUT.PUT_LINE(mtr2yrd(1)); end;
五、在数据字典中查看包的信息
查看包头信息:
SELECT text FROM user_source WHERE name = 'COMM_PKG' AND type = 'PACKAGE';
查看包体信息:
SELECT text FROM user_source WHERE name = 'COMM_PKG' AND type = 'PACKAGE BODY';
六、使用包的优势
1. 模块化: 封装相关的结构
2. 更加容易维护: 将相关的逻辑功能组合到一起
3. 使应用设计更加容易: 包头和包体的编译是分开进行的
4. 隐藏信息:
对于应用,只有声明部分是可见的
包体的私有部分被隐藏并且不能被应用访问
包体中的所有代码被隐藏
5. 提高了性能:
当包第一次被引用的时候,包内的所有内容全部被加载到内存中
对于所有的用户来讲,在内存中只复制一次
简化了依赖性
6. 重载: 多个子程序相同的名
七、删除包
使用如下语法删除包头和包体:
DROP PACKAGE package_name;
删除包体语法:
DROP PACKAGE BODY package_name;