不久前在市檢的生產環境上有個存儲過程執行報錯,錯誤信息如下:
ORA-04068: 已丟棄程序包 的當前狀態 ORA-04061: package "ZHANGXSH.PR_TEST" 的當前狀態失效 ORA-04065: 未執行, 已更改或刪除 package "ZHANGXSH.PR_TEST" ORA-06508: PL/SQL: 無法找到正在調用 : "ZHANGXSH.PR_TEST" 的程序單元 ORA-06512: 在 line 2
當然這個錯誤信息是我在我本機試驗復現的,不是真實的報錯信息,不過都是一樣的
開始懷疑是存儲過程編譯失敗造成,但是經過仔細排查,發現沒有編譯失敗,該包所依賴的其他過程、函數、視圖等都沒有問題。仔細分析了下,發現該包里面有多個全局變量,懷疑是全局變量的問題,於是我在本機做了個測試,將該問題復現了下:
首先在會話1中創建以下包:
CREATE OR REPLACE PACKAGE PKG_TEST AS LDLX NUMBER := 1000; END PKG_TEST; / CREATE OR REPLACE PACKAGE BODY PKG_TEST AS END PKG_TEST; /
然后創建測試的存儲過程:
create or replace procedure pr_test2 as begin PKG_TEST.LDLX := PKG_TEST.LDLX+110; dbms_output.put_line(PKG_TEST.LDLX); end; / 然后在會話2中執行pr_test2; SQL> set serveroutput on SQL> exec pr_test2; 1110 PL/SQL procedure successfully completed
可以成功執行。
然后回到會話1中重新編譯PKG_TEST 包。再回到會話2執行存儲過程:
SQL> / begin pr_test2; end; ORA-04068: 已丟棄程序包 的當前狀態 ORA-04061: package "ZHANGXSH.PKG_TEST" 的當前狀態失效 ORA-04065: 未執行, 已更改或刪除 package "ZHANGXSH.PKG_TEST" ORA-06508: PL/SQL: 無法找到正在調用 : "ZHANGXSH.PKG_TEST" 的程序單元 ORA-06512: 在 "ZHANGXSH.PR_TEST2", line 3 ORA-06512: 在 line 2 SQL>
此時,該錯誤立刻被拋出,原因就是全局變量在會話2中存在一個拷貝,當會話不關閉時,該拷貝會一直存在於pga中,如果該包在此時被重新編譯會導致該拷貝失效而報錯。在實際測試中發現,該錯誤出現的概率約為60%左右,也就是說重新編譯100次,約會出現60次,而且詭異的是在rh5+10G下面居然不出現該錯誤,只有當全局變量的值改變時才報該錯。原因有待進一步研究。
因此,很多人包括我自己都偏愛存儲過程,原因之一就是修改后無需重啟中間件立刻生效,這個案例說明,存儲過程也是可能發生問題的,因此提供以下避免的方法:
1.全局變量不要和相關的函數、存儲過程定義在一個包里面,而是單獨定義,單獨定義的目的是減少被重新編譯的概率。 2.不要使用全局變量,如果要使用,則參考1.
如果已經發生了該錯誤,解決辦法如下:
1.將運行報錯的會話kill掉。 2.刷新共享區:alter system flush shared_pool;