傳遞子程序參數的方式有兩種--傳值和傳引用。當以引用的方式傳遞參數的時候,就將指向實際參數的一個指針傳遞到相應的形式參數。另外一方面,當以傳值的方式傳遞參數的時候,就將實際參數的值複製到相應的形式參數。以引用的方式傳遞參數一般會更快,由於它避免了複製。對集合類型的參數而言,這表現更加明顯,由於集合類型的數據通常都很是多。數組
默認狀況下,PL/SQL對IN參數都使用傳引用的方式,而對IN OUT和OUT參數都使用傳值的方式。測試
一、NOCOPY的使用方法spa
parameter_name [mode] NOCOPY datatype.net
其中parameter_name是參數的名稱,mode是參數模式,而datatype是參數類型。若是有NOCOPY,PL/SQL編譯器就會嘗試經過傳引用的方式傳遞參數,而不是經過傳值方式傳遞參數。注意,NOCPY只是一個編譯器提示,而不是編譯器命令,所以,這種提示並不必定總會被接受。指針
1 create or replace procedure no_copy_proc ( 2 p_inparam in number , 3 p_outparam out nocopy varchar2 , 4 p_inoutparam in out nocopy varchar2 5 )as 6 begin 7 null ; 8 end ;
在IN參數上使用NOCOPY時,會引起一個編譯錯誤,由於IN參數老是以傳引用方式傳遞參數的,所以不容許使用編譯器提示NOCOPY。code
二、帶NOCOPY的異常語義blog
使用NOCOPY即便出現異常,NOCOPY也會自動處理。rem
以傳遞引用的方式傳遞參數的時候,對形式參數所作的任何更改都會同時反應到實際參數上,由於這兩者指向的是同一個位置。這也意味着,若是過程在形式參數的值發生了變化之後,又以一個未處理的異常結束,那麼在過程體內修改參數的值將會丟失。編譯器
(1)例子:io
1 declare 2 v_a number := 10 ; --定義變量 3 v_b number := 20 ; 4 procedure chenge_proc ( 5 p_a in out number , --定義參數 6 p_b in out nocopy number 7 )as 8 begin 9 p_a := 100 ; --修改參數內容 10 p_b := 100 ; --修改參數最直接的影響就是影響原始數據。 11 RAISE_APPLICATION_ERROR(-20001, '測試NOCOPY') ; --拋出異常 12 end ; 13 begin 14 DBMS_OUTPUT.PUT_LINE('過程調用以前:v_a :' || V_A || ' ---- v_b : ' || V_B) ; 15 begin 16 chenge_proc(v_a , v_b) ; --傳遞參數 17 exception 18 when others then 19 DBMS_OUTPUT.PUT_LINE('SQLCODE : ' || SQLCODE || ' , SQLERRM :' || SQLERRM) ; 20 end ; 21 DBMS_OUTPUT.PUT_LINE('過程調用以後:v_a :' || V_A || ' ---- v_b : ' || V_B) ; 22 end ;
(1)執行結果
1 過程調用以前:v_a :10 ---- v_b : 20 2 SQLCODE : -20001 , SQLERRM :ORA-20001: 測試NOCOPY 3 過程調用以後:v_a :10 ---- v_b : 100
咱們能夠看到,發生了異常,使用了NOCOPY的P_B修改了實際參數的值,而p_a並無。
(2)例子:
1 CREATE OR REPLACE PROCEDURE RaiseErrorNoCopy ( -- 建立過程 2 p_Raise IN BOOLEAN, 3 p_ParameterA OUT NOCOPY NUMBER 4 ) AS 5 BEGIN 6 p_ParameterA := 7; -- 修改實際參數的值 7 IF p_Raise THEN 8 RAISE DUP_VAL_ON_INDEX; --p_Raise爲TRUE拋出異常 9 ELSE 10 RETURN; 11 END IF; 12 END RaiseErrorNoCopy;
(2)執行結果
1 DECLARE 2 v_Num NUMBER := 1; -- 定義變量 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE('過程調用以前:' || v_Num); 5 RaiseErrorNoCopy(FALSE, v_Num); --調用過程 6 DBMS_OUTPUT.PUT_LINE('過程調用以後: ' || v_Num); 7 DBMS_OUTPUT.PUT_LINE(''); 8 9 v_Num := 2; --修改變量值 10 DBMS_OUTPUT.PUT_LINE('過程調用以前: ' || v_Num); 11 RaiseErrorNoCopy(TRUE, v_Num); --調用過程將會有異常拋出 12 EXCEPTION 13 WHEN OTHERS THEN --處理異常 14 DBMS_OUTPUT.PUT_LINE('過程調用以後: ' || v_Num); 15 END;
咱們能夠看到,即便發生了異常,仍是兩次修改了實際參數的值。
三、使用NOCOPY的一些限制
在某些狀況下,編譯器會忽略NOCOPY的存在,參數仍然以傳值的方式進行傳遞,並且也不會產生任何錯誤。記住,NOCOPY只是一種pragma,編譯器沒有責任徹底遵照這個提示。在下面幾種情形中,會忽略NOCOPY的存在:
【轉】http://blog.csdn.net/rudygao/article/details/24348795