关于ora-04065和ora-04068的原理解释
来源:互联网 发布:网络稳定性测试工具 编辑:程序博客网 时间:2024/06/05 11:56
转自:http://tech.it168.com/oldarticle/2006-05-26/200605252326345.shtml
今天在运行一个过程是报了一个ORA-4068错误。虽然问题很简单,而且也很容易解决,但是要真正理解的错误产生的原因,还需要对概念理解的比较清晰。
下面做一个简单的例子重现错误:
SQL> CREATE TABLE T AS SELECT * FROM TAB;
表已创建。
SQL> CREATE OR REPLACE PROCEDURE P_RECREATE AS
2 BEGIN
3 EXECUTE IMMEDIATE 'DROP TABLE T';
4 EXECUTE IMMEDIATE 'CREATE TABLE T AS SELECT * FROM TAB';
5 END;
6 /
过程已创建。
SQL> CREATE OR REPLACE PROCEDURE P_INSERT_T AS
2 BEGIN
3 INSERT INTO T SELECT * FROM T;
4 END;
5 /
过程已创建。
SQL> BEGIN
2 P_RECREATE;
3 P_INSERT_T;
4 END;
5 /
BEGIN
*第 1 行出现错误:
ORA-04068: 已丢弃程序包 的当前状态
ORA-04065: 未执行, 已更改或删除 stored procedure "YANGTK.P_INSERT_T"
ORA-06508: PL/SQL: 无法找到正在调用 : "YANGTK.P_INSERT_T" 的程序单元
ORA-06512: 在 line 3
如果单独执行两个过程,则不会报错:
SQL> EXEC P_RECREATE PL/SQL 过程已成功完成。 SQL> EXEC P_INSERT_T PL/SQL 过程已成功完成。
看到ORA-04068错误,我首先想到的是由于在P_RECREATE过程中,对表进行了删除重建工作,导致和这个表相关的存储过程变为INVALID。
于是,我尝试在调用过程之前重编译P_INSERT_T过程:
SQL> BEGIN
2 P_RECREATE;
3 EXECUTE IMMEDIATE 'ALTER PROCEDURE P_INSERT_T COMPILE';
4 P_INSERT_T;
5 END;
6 /
BEGIN
*第 1 行出现错误:
ORA-04068: 已丢弃程序包 的当前状态
ORA-04065: 未执行, 已更改或删除 stored procedure "YANGTK.P_INSERT_T"
ORA-06508: PL/SQL: 无法找到正在调用 : "YANGTK.P_INSERT_T" 的程序单元
ORA-06512: 在 line 4
但是发现,错误依旧。
SQL> BEGIN
2 P_RECREATE;
3 EXECUTE IMMEDIATE 'BEGIN P_INSERT_T; END;';
4 END;
5 /
PL/SQL 过程已成功完成。
但如果使用动态SQL的方式调用P_INSERT_T过程,则不会报错。
问题已经基本上清楚了,但是要想说明白,还需要从头说起。
存储过程在编译时,自动检查语法错误、权限以及所有对象依赖性等。等到执行的时候,Oracle不会再进行类似的检查,而是直接运行过程,这也是存储过程拥有较高效率的一个原因。
当存储过程依赖的对象发生变化了,Oralce会自动将存储过程的状态置为INVALID,而存储过程的状态如果为INVALID,则会在下次执行的时候尝试重新编译,如果编译通过,则继续执行,编译失败则报错。
这就是为什么两个过程单独执行时不会报错。
那么,为什么两个过程放到一起执行就会报错,即使尝试重新编译也无效呢。这是由于导致过程P_INSERT_T失效的过程就在调用P_INSERT_T过程的匿名块中。在将匿名块提交给Oracle时,Oracle对里面每个过程的状态进行了检查,由于导致P_INSERT_T失效的P_RECREATE过程还没有执行,这时候,所有过程的状态都是VALID,于是Oracle记录下来过程的信息准备到直接运行。但是调用P_RECREATE过程后,由于T表被删除重建,P_INSERT_T的状态发生变化,但是Oracle对过程P_INSERT_T的检查已经完成,因此在尝试直接运行P_INSERT_T的代码的时候发现P_INSERT_T的状态已经发生变化,因此,这里报错ORA-04068,同样的道理,即使对P_INSERT_T进行了重新编译,Oracle在执行时发现检查时的代码已经发生了变化,仍然会报错,即使这个时候存储过程的状态已经时VALID了。
而采用动态SQL不会报错的原因就更容易理解了,由于采用动态SQL,Oracle将编译是进行的操作推迟到运行时进行,也就是说,Oracle会在调用P_RECREATE 之后,调用P_INSERT_T过程之前对P_INSERT_T进行检查并重新编译,因此,采用动态SQL不会报错。
- 关于ora-04065和ora-04068的原理解释
- 【好文共分享】关于ora-04065和ora-04068的原理解释
- ORA-04068和ORA-04065
- 关于ORA-01034 和ORA-27101报错的处理
- 关于ORA-01034和ORA-27101的一种解决方法
- 关于ORA-01034和ORA-27101的一种解决方法
- 关于ORA-01034和ORA-27101的一种解决方法
- 关于ORA-01034和ORA-27101的一种解决方法
- 关于ORA-01034和ORA-27101的一种解决方法
- 关于ORA-01034和ORA-27101的解决方法
- 关于tnsnames.ora和listener.ora的作用
- 关于ORA-01034和ORA-27101的一种解决方法
- 关于oracle的ORA-00607和ORA-00600错误解决方法
- 关于ORA-01034和ORA-27101的一种解决方法
- 关于ORA-01034和ORA-27101的一种解决方法
- 关于ORA-01034 和ORA-27101报错的处理
- 关于ORA-00979 不是 GROUP BY 表达式错误的解释
- 关于ORA-00979 不是 GROUP BY 表达式错误的解释
- Fragment与FragmentAcitvity间的传值
- C++面型对象程序 (电子工业出版社)设计课后习题第三章最后两题
- SmartFoxServer项目总结
- 页面禁用 鼠标右键
- linux中常用的头文件
- 关于ora-04065和ora-04068的原理解释
- Matlab图形显示
- 不让自己的应用程序在桌面的图标列表里启动显示的方法
- codeforces-363A. Soroban
- Linux中Kill进程的N种方法
- C#对象序列化
- 未结束的字符串常量js
- ubuntu ufw 防火墙
- Windows下USB磁盘开发系列三:枚举系统中U盘、并获取其设备信息