包是一組相關過程、函數、變量、常量和遊標等PL/SQL程序設計元素的組合,它具備面向對象程序設計語言的特色,是對這些PL/SQL 程序設計元素的封裝。包相似於C++和JAVA語言中的類,其中變量至關於類中的成員變量,過程和函數至關於類方法。把相關的模塊歸類成爲包,可以使開發人員利用面向對象的方法進行存儲過程的開發,從而提升系統性能。java
與類相同,包中的程序元素也分爲公用元素和私用元素兩種,這兩種元素的區別是他們容許訪問的程序範圍不一樣,即它們的做用域不一樣。公用元素不只能夠被包中的函數、過程所調用,也能夠被包外的PL/SQL程序訪問,而私有元素只能被包內的函數和過程序所訪問。sql
在PL/SQL程序設計中,使用包不只可使程序設計模塊化,對外隱藏包內所使用的信息(經過使用私用變量),並且能夠提升程序的執行效率。由於,當程序首次調用包內函數或過程時,ORACLE將整個包調入內存,當再次訪問包內元素時,ORACLE直接從內存中讀取,而不須要進行磁盤I/O操做,從而使程序執行效率獲得提升 數據庫
一個包由兩個分開的部分組成:模塊化
包定義(PACKAGE):包定義部分聲明包內數據類型、變量、常量、遊標、子程序和異常錯誤處理等元素,這些元素爲包的公有元素。函數
包主體(PACKAGE BODY):包主體則是包定義部分的具體實現,它定義了包定義部分所聲明的遊標和子程序,在包主體中還能夠聲明包的私有元素。工具
包定義和包主體分開編譯,並做爲兩部分分開的對象存放在數據庫字典中。性能
包定義的語法以下:學習
CREATE [OR REPLACE] PACKAGE package_name {IS | AS} [公有數據類型定義[公有數據類型定義]…] [公有遊標聲明[公有遊標聲明]…] [公有變量、常量聲明[公有變量、常量聲明]…] [公有子程序聲明[公有子程序聲明]…] END [package_name];
包體定義的格式:開發工具
CREATE [OR REPLACE] PACKAGE BODY package_name {IS | AS} [私有數據類型定義[私有數據類型定義]…] [私有變量、常量聲明[私有變量、常量聲明]…] [私有子程序聲明和定義[私有子程序聲明和定義]…] [公有遊標定義[公有遊標定義]…] [公有子程序定義[公有子程序定義]…] [BEGIN PL/SQL 語句] END [package_name];
其中:在包主體定義公有程序時,它們必須與包定義中所聲明子程序的格式徹底一致測試
與開發存儲過程相似,包的開發須要幾個步驟 : 將每一個存儲過程調試正確 用文本編輯軟件將各個存儲過程和函數集成在一塊兒 按照包的定義要求將集成的文本的前面加上包定義 按照包的定義要求將集成的文本的前面加上包主體 使用開發工具進行調式
實例1-包定義:
CREATE OR REPLACE PACKAGE demo_pack IS DeptRec dept%ROWTYPE;--定義變量 FUNCTION add_dept( dept_no NUMBER, dept_name VARCHAR2, location VARCHAR2) RETURN NUMBER;--定義函數 FUNCTION remove_dept(dept_no NUMBER) RETURN NUMBER;--定義函數 PROCEDURE query_dept(dept_no IN NUMBER);--定義存儲過程 END demo_pack;
實例1- 包體定義:
create or replace package body demo_pack is function add_dept(dept_no number,dept_name varchar2,location varchar2) return number is exp_remaining exception; pragma exception_init(exp_remaining,-1);/*非預約義錯誤,-1是違反惟一約束*/ begin insert into dept values(dept_no,dept_name,location); if sql%found then /*隱式遊標,sql*/ return 1; else return 0; end if; exception when exp_remaining then dbms_output.put_line('違反惟一約束.'); end add_dept; function remove_dept(dept_no number) return number is begin delete from dept where deptno=dept_no; if sql%found then return 1; else return 0; end if; end remove_dept; procedure query_dept(dept_no number) is begin select * into DeptRec from dept where deptno=dept_no; dbms_output.put_line('部門編號:'||DeptRec.deptno||',部門名稱:'||DeptRec.dname); exception when no_data_found then dbms_output.put_line('沒有對應部門編號'); when too_many_rows then dbms_output.put_line('查找到了不少條數據'); end query_dept; end demo_pack;
實例1-測試:
begin -- Call the procedure demo_pack.query_dept(dept_no => &no);--&no彈出對話框,輸入值 end;
實例2- 分頁-包定義:
create or replace package pageUtil is type page_cursor is ref cursor;--定義一個遊標類型 procedure pager( tName in varchar2, --表名 pageNum in number, --頁數 pageSize in number,--每頁記錄數 totalRecord out number,--總記錄數 totalPage out number,--總頁數 p_cursor out page_cursor); end pageUtil;
實例2- 分頁-包體定義:
create or replace package body pageUtil is procedure pager( tName in varchar2, --表名 pageNum in number, --頁數 pageSize in number,--每頁記錄數 totalRecord out number,--總記錄數 totalPage out number,--總頁數 p_cursor out page_cursor) is --定義sql語句字符串 v_sql varchar2(1000); --分頁開始位置,與結束位置 v_begin number:=(pageNum-1)*pageSize+1; v_end number:=pageNum*pageSize; begin v_sql:='select * from ( select t.*,rownum rn from ' ||tName||' t where rownum<='||v_end||') where rn>='||v_begin; --把遊標和sql關聯 dbms_output.put_line(v_sql); open p_cursor for v_sql; --計算totalRecord與totalPage v_sql:='select count(*) from '||tName; -- execute immediate v_sql into totalRecord; if mod(totalRecord,pageSize)=0 then totalPage:=totalRecord/pageSize; else totalPage:=totalRecord/pageSize+1; end if; --關閉遊標,這兒須要注意,若是咱們在java程序中使用cursor,那麼就必定不能關閉cursor --不然關閉cursor後,java程序中返回的結果集就是null --close p_cursor; end pager; end pageUtil;
這兒只是一個粗糙的分頁,本身能夠根據需求改進。
PL/SQL 容許對包內子程序和本地子程序進行重載。所謂重載時指兩個或多個子程序有相同的名稱,但擁有不一樣的參數變量、參數順序或參數數據類型
CREATE OR REPLACE PACKAGE demo_pack1 IS DeptRec dept%ROWTYPE; FUNCTION query_dept(dept_no IN NUMBER) RETURN INTEGER; FUNCTION query_dept(dept_no IN VARCHAR2) RETURN INTEGER; END demo_pack1;
注意:
若是兩個子程序的參數只是名稱和方式不一樣時,不能重載他們。
例:PROCEDURE OverlodeMe(P_parameter in number)
PROCEDURE OverlodeMe(P_parameter out number)
不能只根據兩個函數的返回類型進行重載
例:FUNCTION Overlodeme RETURN date
FUNCTION Overlodeme RETURN boolean
重載函數的參數必須在類型系列方面有所不一樣,既不能再同一類 型系列上重載
例:PROCEDURE OverlodeMe(P_parameter in char)
PROCEDURE OverlodeMe(P_parameter out varchar2)
可使用 DROP PACKAGE 命令對不須要的包進行刪除,語法以下:
DROP PACKAGE [BODY] [user.]package_name
例:DROP PACKAGE emp_package;
包所涉及到的數據字典視圖:
DBA_SOURCE, USER_SOURCE, USER_ERRORS, DBA_OBJECTS