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

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

默認狀況下,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的存在:

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

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

相關文章
相關標籤/搜索