package的全局变量特性

来源:互联网 发布:模板制作软件 编辑:程序博客网 时间:2024/05/29 16:05

摘要:

Oracle中的package对象是其他数据库中所不存在的特性之一,这是oracle面向对象编程的一种体现.我们可以像定义面向对象语言的对象一样定义oraclepackage.并为package定义对应的属性(全局变量)和方法(function,procedure).

    package的全局变量在oracle编程过程中有很多有趣并非常实用的作用.比如,我们可以利用这个特性定义带参数的视图,以增加特定情况下(无法通过普通视图完成数据的筛选过程)程序的可维护性.

    本文利用几个测试简单描述package的全局变量特性和用法.

Oracle官方文档中的相关解释:

in   the   same   session   ,  

  the   variable   declared   in   the   package   header   will   not   be   reset   (   global   in   the   session   level   )

  in   different   session   (   database   wise   )   ,   they   are   not   global.  

  So   usually   we   need   to   write   some   reset   variable   function   in   the   beginning   of       the   package   so   that   we   will   not   get   confused   (   in   same   session)

    可以看出, oraclepackage的全局变量的全局性是基于session级别的.session级别设置,修改,维护全局变量的过程不会传输到其他的session.

    我们可以这样理解,oraclepackage封装为一个类.在每个session第一次调用时为这个类创立一个实例.session结束后自动释放实例资源.

package的全局变量特性测试.

   

第一步,创建包含全局变量的package.程序包PKG_TEST.

CREATE OR REPLACE PACKAGE PKG_TEST

IS

  PROCEDURE P_1(v1 VARCHAR2,v2 VARCHAR2);

  PROCEDURE P_2(v1 VARCHAR2,v2 VARCHAR2);

END;

 

CREATE OR REPLACE PACKAGE BODY PKG_TEST

IS

  G_1 VARCHAR2(20);

  G_2 VARCHAR2(20);

 

  PROCEDURE P_1(v1 VARCHAR2,v2 VARCHAR2)

  IS

  BEGIN

    G_1 := v1;

    G_2 := v2;

   

    dbms_output.put_line('G1:'||G_1);

    dbms_output.put_line('G2:'||G_2);

  END;

 

  PROCEDURE P_2(v1 VARCHAR2,v2 VARCHAR2)

  IS

  BEGIN

    G_1 := v1;

    G_2 := v2;

   

    dbms_output.put_line('G1:'||G_1);

    dbms_output.put_line('G2:'||G_2);

  END;

 

 

BEGIN

  G_1 := 0;

  G_2 := 0;

END PKG_TEST;

我们在程序包PKG_TEST中定义了两个全局变量G_1G_2.在每次调用pkg_test,我们将两个数据的值都初始化为0.另外定义了两个过程P_1P_2,都是将传入的参数值赋给G_1G_2.

第二步, session1中执行单步测试过程P_1并传入两个参数v1=1,v2=1.

begin

  -- Call the procedure

  pkg_test.p_1(v1 => 1,

               v2 => 1);

end;

单步运行过程到G_2:=V2,这时两个变量的值都已经被修改为1.

    暂停测试P_1的过程.

第三步,另外开启session,调用过程P2.

    Begin

       PKG_TEST.P_2(2,2);

    End;

    我们看到最后输出的内容如下.

    G1:2

G2:2

第四步, 然后回到session1,将过程P_1剩余的代码执行结束.发现输出结果如下.

G1:1

G2:1

测试意图:

    session1给全局变量赋值之后,使用之前有其他session执行了对变量G_1G_2的赋值操作.测试其他session对全局变量的修改会不会影响到当前session已经为变量赋的值.

结论1:

由于package的全局变量在数据库层次上并不可见是public,所以每个session都可以认为是一个被实例化了地package对象.session级别上对全局变量执行的赋值操作并不会被其他session看到.很好地体现了数据的封装性.

结论2:

    由于oraclepackage并没有显式地创建实例,所以package的全局变量跟其他面向对象语言的类的属性还是有区别的.最显著的区别在于这里的全局变量不能作为属性值在其他procedure或者function中进行调用.如果希望达到这样的效果,可以通过在package中定义function来实现.

例如希望通过下述方式调用pkg_test的全局变量是错误的.

CREATE OR REPLACE VIEW v_test

AS

SELECT decode(pkg_test.G_1,'0','零','非零') FROM dual;

这时,oracle会提示错误.

PKG_TEST.G_1无效的标识符.这是因为pkg_test的全局变量是在package body中定义的,所以这个全局变量对oracle的其他对象不可见.

如果我们修改pkg_test的定义,将全局变量放到package中进行定义,这样我们在v_test中虽然可以看到g_1,但依然无法使用该变量的值.因为这个值为了进行封装,database级别并不是公用的.

CREATE OR REPLACE PACKAGE PKG_TEST

IS

 

  G_1 VARCHAR2(20);

  G_2 VARCHAR2(20);

 

  PROCEDURE P_1(v1 VARCHAR2,v2 VARCHAR2);

  PROCEDURE P_2(v1 VARCHAR2,v2 VARCHAR2);

 

END;

再次执行刚才的视图定义,看到报错提示为:

ora-06533:PLS-221G_1不是过程或尚未定义.

解决方式如下.

修改pkg_test的定义,package增加两个函数F_1,F_2,用来返回G_1G_2的数据,这样的两个函数就可以被其他过程引用了.

CREATE OR REPLACE PACKAGE PKG_TEST

IS

  FUNCTION F_1 RETURN VARCHAR2;

  FUNCTION F_2 RETURN VARCHAR2;

END;

 

CREATE OR REPLACE PACKAGE BODY PKG_TEST

IS

 

  G_1 VARCHAR2(20);

  G_2 VARCHAR2(20);

 

  FUNCTION F_1

  RETURN VARCHAR2

  IS

  BEGIN

    RETURN G_1;

  END;

 

  FUNCTION F_2

  RETURN VARCHAR2

  IS

  BEGIN

    RETURN G_1;

  END;

 

 

BEGIN

  G_1 := 0;

  G_2 := 0;

END PKG_TEST;

这时我们就可以成功执行视图的创建了.

CREATE OR REPLACE VIEW v_test

AS

 

SELECT decode(pkg_test.F_1,'0','零','非零') F1 FROM dual;

设想一下这个视图会返回的结果:

1,pkg_test数据包外进行调用时,由于每次调用pkg_test.f_1之前都会将g_1初始化为0,所以一定会得到这个结果.

2,而如果我们在pkg_test数据包的过程中进行调用,则可以预先通过给G_1赋值的不同而得到我们希望得到的结果.

 

原创粉丝点击