zoukankan      html  css  js  c++  java
  • 以传值和传引用的方式传递参数 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

  • 相关阅读:
    使用pca/lda降维
    交叉验证
    各模型选择及工作流程
    岭回归
    线性回归
    K-临近算法(KNN)
    django中的中间件
    django中form组件
    javascript中的词法分析
    Django之Model操作
  • 原文地址:https://www.cnblogs.com/zbj815/p/6855070.html
Copyright © 2011-2022 走看看