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中执行; 会报错:
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* |
那么可以直接删除这个依赖吗??? 不确定.....
参考:
https://www.2cto.com/database/201305/213284.html
http://www.linuxidc.com/Linux/2012-08/67358.htm
http://ema100.blog.sohu.com/253249159.html