ORA-04068/ ORA-04061


1.    重现

如果只在一个会话中操作,是有效的;

在会话1:中创建:

drop package simplepkg;

create or replace package simplepkg as 

   v_globalvar number := 1; 

   procedure updatevar;  

end simplepkg; 

  

 

create or replace package body simplepkg as  

   procedure updatevar is 

   begin 

      v_globalvar := 6;  

      dbms_output.put_line('v_globalvar:'||v_globalvar);

   end updatevar; 

end simplepkg; 

--查看状态

select * from  user_objects aa where aa.object_name='SIMPLEPKG';

在会话2中调用:

begin

 simplepkg.updatevar;

end;

此时可以成功;

然后在会话1中修改包体内容,再编译;

查看状态发现都是有效的;

此时再次在回话2中执行;

会报错:

  1. ORA-04068: 已丢弃程序包  的当前状态
  2. ORA-04061: package "SIMPLEPKG" 的当前状态失效
  3. ORA-04065: 未执行, 已变更或删除 package "'SIMPLEPKG'"
  4. ORA-06508: PL/SQL: 无法找到正在调用 : "'SIMPLEPKG'" 的程序单元

ORA-06512: 在 line2

在会话2中再次执行:会发现就是正常的;

如果你在会话1中删除:drop packagesimplepkg;

重新创建过程;

再到会话2中第一次执行:

还是报错:

小结:

1.编译包体或者都编译;或者你删除了,再创建都会存在这种问题;

2或者其它的session已经先执行过了, 可以正常执行了,但由于各个session各自在本地保留了全局变量的实例, 还是会报错。

3如果仅仅是重新编译,没有改变内容,不会报错;

4.如果不使用全局变量则是正常的;

匿名块依赖于包 SimplePkg。这种相关是编译时的依赖性,也就是在匿名块首次编译时就确定的相关关系。然而,除此之外,由于每个会话都有其自己包变量的副本,所以运行时包变量之间也存在着依赖关系。因此,当重编SimplePkg时,运行时相关就紧随其后,引发了错误ORA-04068并作废了该块。

即在一个会话中调用程序包package时,会生成package中全局变量的副本,如果在另一个会话中对此package进行编译就会使前一个会话中的副本失效;

如何解决呢?

第一种:捕获这种异常,再执行一次

public static boolean returnExecutionRequired(SQLException e){

            boolean returnValue="72000".equals(e.getSQLState()) && e.getErrorCode()==4068;

                        return returnValue;

            }

 

第二种:

用于复位当前会话的所有包,并且会释放包状态

清理:exec dbms_session.reset_package; 这样就不会报错

 

第三种:重新编译依赖对象

先查询那些依赖的时间戳不一致:

select do.obj#       d_obj,

       do.name,

       do.type#      d_type,

       po.obj# p_obj,

       po.name p_name,

       to_char(p_timestamp, 'yyyy-MM-dd HH24:MI:SS') "P_Timestamp",

       to_char(po.stime, 'yyyy-MM-dd HH24:MI:SS') "STIME",

       decode(sign(po.stime - p_timestamp), 0, 'SAME', '*DIFFER*') X

  from sys.obj$ do, sys.dependency$ d, sys.obj$ po

 where P_OBJ# = po.obj#(+)

   and D_OBJ# = do.obj#

   and do.status = 1 /*dependent is valid*/

   and po.status = 1 /*parent is valid*/

   and po.stime != p_timestamp /*parent timestamp not match*/

 order by 2, 1;

 

 

然后从新编译:

declare

  cursor c_sql is

    select distinct 'alter ' || decode(do.type#,

                                       12,

                                       'TRIGGER',

                                       4,

                                       'VIEW',

                                       5,

                                       'SYNONYM',

                                       7,

                                       'PROCEDURE',

                                       8,

                                       'FUNCTION',

                                       9,

                                       'PACKAGE',

                                       11,

                                       'PACKAGE') || ' ' || u.name || '.' ||

                    do.name || ' ' ||

                    decode(do.type#,

                           12,

                           'compile',

                           4,

                           'compile',

                           5,

                           'compile',

                           7,

                           'compile',

                           8,

                           'compile',

                           9,

                           'compile package',

                           11,

                           'compile body') sql_text

      from sys.obj$ do, sys.dependency$ d, sys.obj$ po, sys.user$ u

     where p_obj# = po.obj#(+)

       and d_obj# = do.obj#

       and do.status = 1

       and po.status = 1

       and do.owner# = u.user#

       and po.stime != p_timestamp;

 

  v_sql_text varchar(2000);

begin

  for v_sql in c_sql loop

    v_sql_text := v_sql.sql_text;

    dbms_output.put_line(v_sql_text);

 

    execute immediate v_sql_text;

  end loop;

 

  --commit;

exception

  when others then

    dbms_output.put_line(sqlerrm);

    dbms_output.put_line(v_sql_text);

end;

 


根本原因:

编译对象时导致PLSQL的依赖对象的时间戳发生不一致;


但是我自已这边查到的:

D_OBJ NAME D_TYPE P_OBJ P_NAME P_Timestamp STIME X
74498 ORDER_TYP 13 74497 CUSTOMER_TYP 2016/11/6 16:59 2016/11/6 16:59 *DIFFER*
这个类型为13,表示Type,不能使用上面的sql执行的.....

那么可以直接删除这个依赖吗??? 不确定.....



 

参考:

https://www.2cto.com/database/201305/213284.html

 

http://www.linuxidc.com/Linux/2012-08/67358.htm

 

http://ema100.blog.sohu.com/253249159.html



猜你喜欢

转载自blog.csdn.net/u011165335/article/details/78905241