本章内容
1.包概述
2.包的创建
3.包的调用
4.包重载
5.包的初始化
6.包的持续性
7.包的串行化
8.包的管理
包概述
1、包是包含一个或多个子程序单元(过程、函数等)的容器。
2、包是一种全局结构 。
3、包类型
数据库内置包
用户创建的包
4、包构成
包规范
包体两
1.包规范声明了软件包中所有内容,如过程、函数、游标、类型、异常和变量等,其中过程和函数只包括原型信息,不包含任何子程序代码。
2.包体中包含了在包头中的过程和函数的实现代码。包体中还可以包括在规范中没有声明的变量、游标、类型、异常、过程和函数,但是它们是私有元素,只能由同一包体中其他过程和函数使用。
包的创建
•
创建包规范
•
创建包体
(1)创建包规范
语法
CREATE OR REPLACE PACKAGE package_name
IS|AS
[PRAGMA SERIALLY_RESUABLE]
type_definition|variable_declaration|
exception_declaration|cursor_declaration|
procedure_ declaration|function_ declaration
END [package_name];
注意:元素声明的顺序可以是任意的,但必须先声明后使用;所有元素是可选的;过程和函数的声明只包括原型,不包括具体实现。
创建一个软件包,包括2个变量、2个过程和1个异常。
(2)创建包体
•语法
CREATE OR REPLACE PACKAGE BODY package_name
IS|AS
[PRAGMA SERIALLY_RESUABLE]
type_definition|variable_declaration|
exception_declaration|
cursor_declaration|
procedure_definition |
function_definition
END [package_name];
注意:包体中函数和过程的原型必须与包规范中的声明完全一致;只有在包规范已经创建的条件下,才可以创建包体;如果包规范中不包含任何函数或过程,则可以不创建包体。
CREATE OR REPLACE PACKAGE BODY pkg_emp
AS
PROCEDURE update_sal(p_empno NUMBER, p_sal NUMBER)
AS
BEGIN
SELECT min(sal), max(sal) INTO minsal,maxsal FROM emp;
IF p_sal BETWEEN minsal AND maxsal THEN
UPDATE emp SET sal=p_sal WHERE empno=p_empno;
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20000,'The employee doesn''t exist');
END IF;
ELSE
RAISE e_beyondbound;
END IF;
EXCEPTION
WHEN e_beyondbound THEN
DBMS_OUTPUT.PUT_LINE('The salary is beyond bound! ');
END update_sal;
PROCEDURE add_employee(p_empno NUMBER,p_sal NUMBER)
AS
BEGIN
SELECT min(sal), max(sal) INTO minsal,maxsal FROM emp;
IF p_sal BETWEEN minsal AND maxsal THEN
INSERT INTO emp(empno,sal) VALUES(p_empno,p_sal);
ELSE
RAISE e_beyondbound;
END IF;
EXCEPTION
WHEN e_beyondbound THEN
DBMS_OUTPUT.PUT_LINE('The salary is beyond bound! ');
END add_employee;
END pkg_emp;
包的调用
•
在包规范声明的任何元素是公有的,在包外都是可见的
包外:通过
package.element
形式调用;
包内:直接通过元素名进行调用。
•
在包体中定义而没有在包头中声明的元素是私有的,只能在包体中引用
•
调用软件包
pkg_emp
中的过程
update_sal
,修改
7844
员工工资为
3000
。调用
add_employee
添加一个员工号为
1357
,工资为
4000
的员工。
BEGIN
pkg_emp.update_sal(7844,3000);
pkg_emp.add_employee(1357,4000);
END;
包重载
•
重载子程序必须同名不同参,即名称相同,参数不同。参数不同体现为参数的个数、顺序、类型等不同。
•
如果两个子程序参数只是名称和模式不同,则不能重载。
PROCEDURE
overloadme
(parameter1 IN NUMBER);
PROCEDURE
overloadme
(parameter2 OUT NUMBER);
•
不能根据两个函数返回类型不同而对它们进行重载。
FUNCTION
overloadme
RETURN DATE;
FUNCTION
overloadme
RETURN NUMBER;
•
重载子程序参数必须在类型系列方面有所不同。
PROCEDURE
overloadchar
(parameter IN CHAR);
PROCEDURE
overloadchar
(parameter IN VARCHAR2);
在一个包中重载两个过程,分别以部门号和部门名称为参数,查询相应部门员工名、员工号信息。
CREATE OR REPLACE PACKAGE pkg_overload
AS
PROCEDURE show_emp(p_deptno NUMBER);
PROCEDURE show_emp(p_dname VARCHAR2);
END pkg_overload;
CREATE OR REPLACE PACKAGE BODY pkg_overload
AS
PROCEDURE show_emp(p_deptno NUMBER)
AS
BEGIN
FOR v_emp IN (SELECT * FROM emp WHERE deptno=p_deptno) LOOP
DBMS_OUTPUT.PUT_LINE(v_emp.empno||' '|| v_emp.ename);
END LOOP;
END show_emp;
PROCEDURE show_emp(p_dname VARCHAR2)
AS
v_deptno NUMBER;
BEGIN
SELECT deptno INTO v_deptno FROM dept
WHERE dname=p_dname;
FOR v_emp IN (SELECT * FROM emp
WHERE deptno=v_deptno) LOOP
DBMS_OUTPUT.PUT_LINE(v_emp.empno||' '||
v_emp.ename);
END LOOP;
END show_emp;
END pkg_overload;
包的初始化
•
包在第一次被调用时从磁盘读取到共享池,并在整个会话的持续期间保持。在此过程中,可以自动执行一个初始化过程,对软件包进行实例化。
•
包的初始化过程只在包第一次被调用时执行,因此也称为一次性过程,它是一个匿名的
PL/SQL
块,在包体结构的最后,以
BEGIN
开始。
示例
在
pkg_emp
包中,在包初始化时给
minsal
和
maxsal
两个变量赋值,在子程序中直接引用这两个变量。
CREATE OR REPLACE PACKAGE pkg_emp
AS
minsal NUMBER;
maxsal NUMBER;
e_beyondbound EXCEPTION;
PROCEDURE update_sal(
p_empno NUMBER, p_sal NUMBER);
PROCEDURE add_employee(
p_empno NUMBER,p_sal NUMBER);
END pkg_emp;
CREATE OR REPLACE PACKAGE BODY pkg_emp
AS
PROCEDURE update_sal(p_empno NUMBER, p_sal NUMBER)
AS
BEGIN
IF p_sal BETWEEN minsal AND maxsal THEN
UPDATE emp SET sal=p_sal WHERE empno=p_empno;
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20000,'The employee
doesn''t exist');
END IF;
ELSE
RAISE e_beyondbound;
END IF;
EXCEPTION
WHEN e_beyondbound THEN
DBMS_OUTPUT.PUT_LINE('The salary is beyond bound!');
END update_sal;
PROCEDURE add_employee(p_empno NUMBER,p_sal NUMBER)
AS
BEGIN
IF p_sal BETWEEN minsal AND maxsal THEN
INSERT INTO emp(empno,sal) VALUES(p_empno,p_sal);
ELSE
RAISE e_beyondbound;
END IF;
EXCEPTION
WHEN e_beyondbound THEN
DBMS_OUTPUT.PUT_LINE('The salary is beyond bound!');
END add_employee;
BEGIN
SELECT min(sal), max(sal) INTO minsal,maxsal FROM emp;
END pkg_emp;
包的持续性
•
变量持续性
•
游标持续性
(1)变量持续性
包中变量的持续性是指,当用户调用包时,会创建自己的变量副本,在用户的整个会话过程中持续存在,对用户而言是私有的。
为了测试变量的持续性,先创建一个包含一个变量的包和对包中变量进行读、写的两个过程。
CREATE OR REPLACE PACKAGE variable_pkg
IS
pkg_test NUMBER(6,2) :=0;
END variable_pkg;
CREATE OR REPLACE PROCEDURE get_pkg_test
(p_test OUT NUMBER)
IS
BEGIN
p_test := variable_pkg.pkg_test;
END;
CREATE OR REPLACE PROCEDURE set_pkg_test
(p_test IN NUMBER)
IS
BEGIN
variable_pkg.pkg_test := p_test;
END;
以不同的用户(scott,system)分别启动两个SQL*Plus,进行下列操作,可以看出,包中的变量variable_pkg.pkg_test在scott用户和system用户之间是持续的、独立的。
--user scott
SQL>variable g_test NUMBER;
SQL>EXECUTE get_pkg_test(:g_test);
SQL>PRINT g_test
G_TEST
----------
0
SQL>EXECUTE set_pkg_test(10);
SQL>EXECUTE get_pkg_test(:g_test);
SQL>PRINT g_test
G_TEST
----------
10
--user system
SQL>variable g_test NUMBER
SQL>EXECUTE scott.get_pkg_test(:g_test);
SQL>PRINT g_test
G_TEST
----------
0
SQL>EXECUTE scott.set_pkg_test(20);
SQL>EXECUTE scott.get_pkg_test(:g_test);
SQL>PRINT g_test
G_TEST
----------
20
--user scott
SQL>EXECUTE get_pkg_test(:g_test);
SQL>PRINT g_test
G_TEST
----------
10