日期:2014-05-17  浏览次数:21156 次

plsql连续执行结果不同
用pl/sql   developer测一段pl/sql代码

1.   编译我的pl/sql代码
2.   运行测试程序,得到预期结果。而且我的pl/sql代码中的dbms_output.put_line的输出也会正确显示
3.   然后在不重新编译我的pl/sql代码的前提下,重新运行测试程序(非debug方式),返回结果就不同了,而且dbms_output.put_line的输出没有显示。无论多少遍都是一样

但是如果重新编译pl/sql代码或者以debug方式运行,返回值就总是一致的,而且dbms_output.put_line的输出正确显示

加了PRAGMA   SERIALLY_REUSABLE之后,就不会出现这个现象了,但是我还是有一点不明白,包变量是session级别的,被缓存了可以理解,但是就算是被缓存了,为什么dbms_output的输出为什么没有了呢,而且好像子函数也没有执行(直接就返回了true)。

这是怎么回事啊

------解决方案--------------------
1.pragma serially_reusable是包的特性。

2.如果包中的某个函数或过程被调用,则包会驻留在内存中:包的全局变量会保留,像全局游标,就不会被关闭(如果一个包函数完成的功能是取表中的一个记录,则多次调用这个函数会得到不同的记录)。

但如果使包具有pragma serially_reusable特性,则可以使全局变量“不保留”,使全局游标关闭(2中说的那个函数被多次调用的话,就得到的是同一个记录)。

下面这个例子,结论是:如果没有这个特性,则这两个块执行的结果一样,如果有这个特性,则结果不一样,下面那个块没有输出。

declare
i number;
j varchar2(20);
begin
srPkg1.initialize;---给全局变量赋值
i:=srPkg1.return_num;--返回全局变量
j:=srPkg1.return_char;--返回全局变量
dbms_output.put_line(to_char(i));
dbms_output.put_line(j);
end;

declare
i number;
j varchar2(20);
begin
i:=srPkg1.return_num;
j:=srPkg1.return_char;
dbms_output.put_line(to_char(i));
dbms_output.put_line(j);
end;

这就说明了pragma serially_reusable对包全局变量,游标的影响。
------解决方案--------------------
SERIALLY_REUSABLE, 这个PRAGMA在字面上并不能一下知道它的作用,最起码我没有一下子就知道它的意思,呵呵。

这个指令指出程序包的状态只在第一次与服务器CALL时需要,这个CALL结束后,有关这个程序包的变量的存储可以被重用,这样减少了那些需要长时间运行的会话对内存的过载。

语法,PRAGMA SERIALLY_REUSABLE;

这个编译指令对那些只用到一次的大型的临时工作区的声明并且在同一个会话接下来的数据库调用中不会再用到的程序包适用。

你也可以在程序包体标记这个编译指令,如果一个程序包包括定义及包体的话,两边都要指定这个指令,不能单指一边。

对于拥有这个编译指令的包,Oracle在SGA里为它分配内存,不在UGA里分配,这样,这个程序包的工作区可以被重用,这样就起到了这个编译指令的目的。当程序的调用结束,在SGA分配的相应的内存块返回给内存池。每次这个程序包调用时,它的公共变量初始化为它的默认值或者为NULL。

SERIALLY REUSABLE的程序包不能被数据库触发器或者在SQL语句级别对PL/SQL子程序的调用时访问,不然,Oracle产生相应的错误。

总而言之,这个编译指令主要是出于保护内存考虑,减少不必要的内存负载,充分解了那些长时间运行的会话对内存的占用
------解决方案--------------------
SERIALLY_REUSABLE就是重置这些数据否则只有结束当前会话的时候才会被重置