Oracle之PL/SQL學習筆記之包

Oracle之PL/SQL學習筆記之包

1. 認識包(package)

1.1 什麼是包

         包是一組相關過程、函數、變量、常量和遊標等PL/SQL程序設計元素的組合,它具備面向對象程序設計語言的特色,是對這些PL/SQL 程序設計元素的封裝。包相似於C++和JAVA語言中的類,其中變量至關於類中的成員變量,過程和函數至關於類方法。把相關的模塊歸類成爲包,可以使開發人員利用面向對象的方法進行存儲過程的開發,從而提升系統性能。java

與類相同,包中的程序元素也分爲公用元素和私用元素兩種,這兩種元素的區別是他們容許訪問的程序範圍不一樣,即它們的做用域不一樣。公用元素不只能夠被包中的函數、過程所調用,也能夠被包外的PL/SQL程序訪問,而私有元素只能被包內的函數和過程序所訪問。sql

在PL/SQL程序設計中,使用包不只可使程序設計模塊化,對外隱藏包內所使用的信息(經過使用私用變量),並且能夠提升程序的執行效率。由於,當程序首次調用包內函數或過程時,ORACLE將整個包調入內存,當再次訪問包內元素時,ORACLE直接從內存中讀取,而不須要進行磁盤I/O操做,從而使程序執行效率獲得提升 數據庫


1.2 包的組成

一個包由兩個分開的部分組成:模塊化

   包定義(PACKAGE):包定義部分聲明包內數據類型、變量、常量、遊標、子程序和異常錯誤處理等元素,這些元素爲包的公有元素。函數

   包主體(PACKAGE BODY):包主體則是包定義部分的具體實現,它定義了包定義部分所聲明的遊標和子程序,在包主體中還能夠聲明包的私有元素。工具

   包定義和包主體分開編譯,並做爲兩部分分開的對象存放在數據庫字典中。性能


1.3 包的定義

包定義的語法以下:學習

CREATE [OR REPLACE] PACKAGE package_name
{IS | AS}
		[公有數據類型定義[公有數據類型定義]…]
		[公有遊標聲明[公有遊標聲明]…]
		[公有變量、常量聲明[公有變量、常量聲明]…]
		[公有子程序聲明[公有子程序聲明]…]
END [package_name];


1.4 包體的定義

 包體定義的格式:開發工具

CREATE [OR REPLACE] PACKAGE BODY package_name
{IS | AS}
		[私有數據類型定義[私有數據類型定義]…]
		[私有變量、常量聲明[私有變量、常量聲明]…]
		[私有子程序聲明和定義[私有子程序聲明和定義]…]
		[公有遊標定義[公有遊標定義]…]
		[公有子程序定義[公有子程序定義]…]
[BEGIN
		PL/SQL 語句]
END [package_name];

其中:在包主體定義公有程序時,它們必須與包定義中所聲明子程序的格式徹底一致測試

1.5 包開發步驟

與開發存儲過程相似,包的開發須要幾個步驟 :
    將每一個存儲過程調試正確 
    用文本編輯軟件將各個存儲過程和函數集成在一塊兒 
    按照包的定義要求將集成的文本的前面加上包定義 
    按照包的定義要求將集成的文本的前面加上包主體 
    使用開發工具進行調式


2. 建立包應用實例

實例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;


    這兒只是一個粗糙的分頁,本身能夠根據需求改進。


3. 子程序的重載

      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)


4. 刪除包

    

可使用 DROP PACKAGE 命令對不須要的包進行刪除,語法以下: 


DROP PACKAGE [BODY] [user.]package_name

        例:DROP PACKAGE emp_package; 

包所涉及到的數據字典視圖: 

        DBA_SOURCE, USER_SOURCE, USER_ERRORS, DBA_OBJECTS 

相關文章
相關標籤/搜索