什麼是包
一個PL/SQL包由兩部分組成:
- 包規範:主要是包的一些定義信息,不包含具體的代碼實現,是PL/SQL程序的接口部分,包含類型、記錄、變量、常量、異常定義、遊標和子程序的聲明。
- 包體:包體是對包規範中聲明的子程序的實現部分,包體的內容對於外部應用程序來說是不可見的。
包的優點
- 模塊化設計。
- 規範化的程序設計。
- 實現信息的隱藏。
- 提供全局共享的附加功能:在包中公開的變量或遊標在一個會話期會一直存在,並且可以被當前環境下的所有子程序共享,因此可以將包中定義的變量當做全局變量來使用,並且可以跨事務來維護數據而不用把它保存在數據庫中。
- 提供了良好的性能體驗:由於在首次打開包子程序時,整個包都會被加載到內存中,後續的調用只需要從內存中讀取而不需要再次讀取磁盤。
定義包規範
代碼如下:
--定義包規範,包規範將被用於應用程序的接口部分,供外部調用
CREATE OR REPLACE PACKAGE emp_pkg AS
--定義集合類型
TYPE emp_tab IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
--在包規範中定義一個記錄類型
TYPE emprectyp IS RECORD(
emp_no NUMBER,
sal NUMBER
);
--定義一個遊標變量
CURSOR desc_salary RETURN emprectyp;
--定義僱傭員工的過程
PROCEDURE hire_employee(p_empno NUMBER,p_ename VARCHAR2,p_job VARCHAR2,p_mgr NUMBER,p_sal NUMBER,
p_comm NUMBER,p_deptno NUMBER,p_hiredate DATE);
--定義解僱員工的過程
PROCEDURE fire_employee(p_emp_id NUMBER );
END emp_pkg;
定義包體
代碼如下:
--定義包體
CREATE OR REPLACE PACKAGE BODY emp_pkg
AS
--定義遊標變量的具體類型
CURSOR desc_salary RETURN emprectyp IS
SELECT empno, sal FROM emp ORDER BY sal DESC;
--定義僱傭員工的具體實現
PROCEDURE hire_employee(p_empno NUMBER,p_ename VARCHAR2,
p_job VARCHAR2,p_mgr NUMBER,p_sal NUMBER,
p_comm NUMBER,p_deptno NUMBER,p_hiredate DATE) IS
BEGIN
--向emp表中插入一條員工信息
INSERT INTO emp VALUES(p_empno,p_ename,p_job,p_mgr,p_hiredate,p_sal,p_comm,p_deptno);
END;
--定義解僱員工的具體實現
PROCEDURE fire_employee(p_emp_id NUMBER ) IS
BEGIN
--從emp表中刪除員工信息
DELETE FROM emp WHERE empno=p_emp_id;
END;
END emp_pkg;
調用包組件
當包被第一次調用時,將進行初始化,比如將包從硬盤上調到內存中來,放到系統全局工作區的共享緩衝池中,包的運行狀態則被放入用戶全局區的會話存儲區中。因此可以保證每個調用報的會話都擁有包的運行副本,當會話結束時,包的運行狀態纔會被釋放。因此包中的變量具有會話級的作用域,因而可以跨多個事務存儲數據。
包的這種特性使得我們可以在包中保存跨多個事務的數據,這大大方便了複雜的程序邏輯的中間數據的存儲,而不用特意用一個表來存儲臨時的數據。
如果在定義包規範時,指定了編譯提示SERIALLY_REUSABLE
,則可以將包的運行狀態保存在系統全局工作區,而不是用戶全局區,這樣每次調用包以後,包的運行狀態就會被釋放,這樣再次調用包時,將重新開始包的狀態。
PRAGMA SERIALLY_REUSABLE;
不過這種每次調用便釋放的連續進行會佔用大量的內存,內存的佔用量與包的併發調用用戶數成正比,而與當前登錄的用戶數無關,因此需要謹慎使用。
編譯和調試包
可以使用PL/SQL Developer的調試功能進行可視化的調試和編譯,也可以使用ALTER PACKAGE語句來重新編譯包。
ALTER PACKAGE emp_pkg COMPILE BODY; --編譯包體
ALTER PACKAGE emp_pkg COMPILE PACKAGE; --編譯包規範和包體
ALTER PACKAGE emp_pkg COMPILE SPECIFICATION; --編譯包規範
顯式地對包進行重新編譯可以清楚運行階段的隱式編譯,這樣可以防止在運行時的編譯錯誤及所帶來的性能開銷。
查看包的源代碼
與子程序一樣,可以查詢user_objects
視圖來查看數據字典中包含的包的信息。
SELECT object_type, object_name, status
FROM user_objects
WHERE object_type IN ('PACKAGE', 'PACKAGE BODY');
也可以從user_source
視圖中獲取包的源代碼,
SELECT line, text
FROM user_source
WHERE NAME = 'EMP_ACTION_PKG' AND TYPE = 'PACKAGE'
ORDER BY line;
SELECT line, text
FROM user_source
WHERE NAME = 'EMP_ACTION_PKG' AND TYPE = 'PACKAGE BODY'
ORDER BY line;