PL/SQL包的概念和特点、包结构和定义(包定义(PACKAGE)、包主体(PACKAGE BODY)、包的其他命令)


包的概念和特点

在一个大型项目中,可能有很多模块,而每个模块又有自己的过程、函数等。而这些过程、函数默认是放在一起的(如在PL/SQL中,过程默认都是放在一起的,即Procedures中),这些非常不方便查询和维护,甚至会发生误删除的事件。

PL/SQL为了满足程序模块化的需要,引入了包的构造。通过使用包就可以分类管理过程和函数等。

1)包是一种数据库对象,相当于一个容器。将逻辑上相关的过程、函数、变量、常量和游标组合成一个更大的单位。用户可以从其他 PL/SQL 块中对其进行引用

2)包类似于C++和JAVA语言中的类,其中变量相当于类中的成员变量,过程和函数相当于类方法。把相关的模块归类成为包,可使开发人员利用面向对象的方法进行开发,具有面向对象程序设计语言的特点

3)PL/SQL的包具有信息隐蔽性(information hiding),仅在算法和数据结构设计有关层可见。可将过程说明和过程体组成一个程序单位。也可将过程说明与它的过程体分开。也可在包中定义过程,而该过程在包说明中没有定义过程说明,这样定义的过程仅在包内使用。

4)在PL/SQL程序设计中,使用包不仅可以使程序设计模块化,对外隐藏包内所使用的信息(通过使用私用变量),而写可以提高程序的执行效率。因为,当程序首次调用包内函数或过程时,ORACLE将整个包调入内存,当再次访问包内元素时,ORACLE直接从内存中读取,而不需要进行磁盘I/O操作,从而使程序执行效率得到提高。

包结构和定义

一个包由两个分开的部分组成:包规范和包体

包定义(PACKAGE)

包定义部分是为应用程序的接口,声明包内数据类型、变量、常量、游标、子程序和异常错误处理等元素,这些元素为包的公有元素。

CREATE [OR REPLACE] PACKAGE package_name
{IS | AS}
	[公有数据类型定义]
	[公有游标声明]
	[公有变量、常量声明]
	[公有子程序声明]
END [package_name];

----实例
CREATE OR REPLACE PACKAGE PACKAGENAME
IS
  PROCEDURE P1(A VARCHAR2,I  OUT NUMBER);
  PROCEDURE P2(A VARCHAR2, I  OUT NUMBER);
  PROCEDURE P3(A VARCHAR2/*,I  OUT NUMBER*/);
  ....
END;

包主体(PACKAGE BODY)

包主体(PACKAGE BODY):包主体则是包定义部分的具体实现,它定义了包定义部分所声明的游标和子程序,在包主体中还可以声明包的私有元素

如果在包主体中的游标或子程序并没有在包头中定义,那么这个游标或子程序是私有的。

CREATE [OR REPLACE] PACKAGE BODY package_name
{IS | AS}
	[私有数据类型定义]
	[私有变量、常量声明]
	[私有子程序声明和定义]
	[公有子程序定义]
BEGIN
	执行部分(初始化部分)
END [package_name];

--实例
CREATE OR REPLACE PACKAGE BODY PACKAGE1 
IS
	PROCEDURE P1(A IN VARCHAR2, I OUT NUMBER) 
	IS
    	C VARCHAR2(32000);    
   	    D VARCHAR2(32000); 
	BEGIN
		..... 
    END;
    
	PROCEDURE P2(A IN VARCHAR2,I OUT NUMBER) 
	IS   
	    C VARCHAR2(32000);    
	    D VARCHAR2(32000);  
	BEGIN	
		......
	END;
	
	PROCEDURE P3(A IN VARCHAR2) 
	IS  
	BEGIN	
		.....  
	END;
END PACKAGE1;

与类相同,包中的程序元素也分为公用元素和私用元素两种,这两种元素的区别是他们允许访问的程序范围不同,即它们的作用域不同。

公用元素不仅可以被包中的函数、过程所调用,也可以被包外的PL/SQL程序访问,而私有元素只能被包内的函数和过程序所访问。

包定义和包主体分开编译,并作为两部分分开的对象存放在数据库字典中。

包定义一定要在包主体前面编译(包主体可以没有,但包定义一定要有),包的名称和包体的名称要保持一致。

当使用包的公用函数时,它既可以作为表达式的一部分使用,也可以在SQL语句中使用。但如果要在SQL语句中引用包的公用函数,那么该公用函数不能包含DML语句(INSERT、UPDATE和DELETE),也不能读写远程包的变量。为了对的公用函数加以限制,在定义包规范时可以使用纯度级别(purity level)限制公用函数。定义纯度级别的语法如下:

PRAGMA RESTRICT_REFERENCES (function_name, WNDS[,WNPS][,RNDS][,RNPS]);
/*WNDS:用于限制函数不能修改数据库数据(即禁止执行DML操作)。
WNPS:用于限制函数不能修改包变量(即不能给包变量赋值)。
RNDS:用于限制函数不能读取数据库数据(即禁止执行SELECT操作)。
RNPS:用于限制函数不能读取包变量(即不能将包变量赋值给其他变量)。*/

示例一、根据输入的部门编号找到这个部门的所有员工

--首先创建包,定义包规范
create or replace package getemp_pkg is
  FUNCTION getemp_fun(p_dno dept.deptno%type) RETURN SYS_REFCURSOR; --返回弱类型游标
end getemp_pkg;

--定义包的主体
create or replace package body getemp_pkg 
as
	FUNCTION getemp_fun(p_dno dept.deptno%TYPE) 
	RETURN SYS_REFCURSOR                --返回弱类型游标
	AS
		cur_emp   SYS_REFCURSOR;
	BEGIN
	   OPEN cur_emp FOR SELECT * FROM emp WHERE deptno=p_dno;          --打开游标
	   RETURN cur_emp;             --返回游标
	END getemp_fun;
end getemp_pkg;

--调用包
DECLARE
  V_EMP   EMP%ROWTYPE;                   --定义变量来接收游标的内容
  CUR_EMP SYS_REFCURSOR;                --定义游标来接收返回游标
  V_DNO   DEPT.DEPTNO%TYPE;                --定义部门编号,转入参数
BEGIN
  CUR_EMP := GETEMP_PKG.GETEMP_FUN(&V_DNO);
  LOOP
    FETCH CUR_EMP                                       --提取游标
      INTO V_EMP;
    EXIT WHEN CUR_EMP%NOTFOUND;                  --退出条件
    DBMS_OUTPUT.PUT_LINE(CUR_EMP%ROWCOUNT || ' 员工编号:' || V_EMP.EMPNO ||
                         ' 姓名:' || V_EMP.ENAME);
  END LOOP;
  CLOSE cur_emp;                                    --关闭游标
END;

示例二、包中有过程和函数

--程序包规范
create or replace package pack_me is
	PROCEDURE emp_proc(num NUMBER);
	FUNCTION emp_fun(eno NUMBER) RETURN VARCHAR2;
end pack_me;

--程序包主体
create or replace package body pack_me is
	PROCEDURE emp_proc(num NUMBER) 
	IS
		v_name     VARCHAR2(50);
	BEGIN
	  SELECT ename INTO v_name FROM emp WHERE empno=num;
	  dbms_output.put_line('员工编号:'||num||' 的姓名:'||v_name);
	END emp_proc;
	
	FUNCTION  emp_fun(eno NUMBER) RETURN VARCHAR2
	AS
		v_job          varchar2(50);
	BEGIN
		SELECT job INTO v_job FROM emp WHERE empno=eno;
		RETURN v_job;
		--dbms_output.put_line('员工编号:'||empno||' 的职位:'||v_job);
	END emp_fun;
end pack_me;

--执行
DECLARE
	v_empno         emp.empno%TYPE:=&empno;
	v_job           varchar2(50);
BEGIN
	pack_me.emp_proc(v_empno);
	v_job:=pack_me.emp_fun(v_empno);
	dbms_output.put_line('员工编号:'||v_empno||' 的职位:'||v_job);
END;

包的其他命令

1、查询user_objects数据字典确认包规范及包体

SELECT object_type,object_name,status 
FROM User_Objects 
WHERE object_type IN('PACKAGE','PACKAGE BODY');

2、 查询包的内容

SELECT * FROM user_source WHERE TYPE = 'PACKAGE' AND NAME = 'GETEMP_PKG';

3、删除包(删除包规范里会对其对应的包体一起删除)

删除包规范

DROP PACKAGE 包名称

删除包体

DROP PACKAGE BODY 包名称

4、 包的重新编译

ALTER PACKAGE 包名称 COMPILE PACKAGE;
--示例
ALTER PACKAGE GETEMP_PKG COMPILE PACKAGE;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值