以傳值和傳引用的方式傳遞參數 IN OUT NOCOPY


傳遞子程序參數的方式有兩種--傳值和傳引用。當以引用的方式傳遞參數的時候,就將指向實際參數的一個指針傳遞到相應的形式參數。另一方面,當以傳值的方式傳遞參數的時候,就將實際參數的值復制到相應的形式參數。以引用的方式傳遞參數通常會更快,因為它避免了復制。對集合類型的參數而言,這表現更加明顯,因為集合類型的數據一般都非常多。

默認情況下,PL/SQL對IN參數都使用傳引用的方式,而對IN OUT和OUT參數都使用傳值的方式。

 

1、NOCOPY的使用方法

parameter_name [mode] NOCOPY datatype

其中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。

 

2、帶NOCOPY的異常語義

使用NOCOPY即使出現異常,NOCOPY也會自動處理。

以傳遞引用的方式傳遞參數的時候,對形式參數所做的任何更改都會同時反應到實際參數上,因為這二者指向的是同一個位置。這也意味着,如果過程在形式參數的值發生了變化以后,又以一個未處理的異常結束,那么在過程體內修改參數的值將會丟失。

 (1)例子:

 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;  

我們可以看到,即使發生了異常,還是兩次修改了實際參數的值。

3、使用NOCOPY的一些限制

在某些情況下,編譯器會忽略NOCOPY的存在,參數仍然以傳值的方式進行傳遞,而且也不會產生任何錯誤。記住,NOCOPY只是一種pragma,編譯器沒有責任完全遵守這個提示。在下面幾種情形中,會忽略NOCOPY的存在:

  • 實際參數是聯合數組的一個成員。但是,如果實際參數是整個數組,就不受這種約束的限制。
  • 使用長度、精度或NOT NULL約束限制的實際參數。
  • 實際參數和形式參數都是記錄,並且它們要么被隱式聲明為一個循環變量,要么是使用%ROWTYPE進行聲明的,而且相應字段上的約束又不同。
  • 傳遞的實際參數需要進行隱式的數據類型轉換。
  • 子程序被包含在進行遠程過程調用(remote procedures call,RPC)中。

【轉】http://blog.csdn.net/rudygao/article/details/24348795


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM