過程執行報錯ORA 4068

2021-06-18 11:35:15 字數 2542 閱讀 8828

今天在執行乙個過程是報了乙個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" 的程式單元

ixdba.net社群論壇

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 01031

a使用者呼叫b使用者的儲存過程,如果儲存過程中有動態建表的sql語句,如create table test,那麼管理員 如dba 必須給b使用者賦予create table的許可權,即使b已經是dba角色也必須單獨授予建表的許可權 如果是create table a.test,則必須給b使用者授予c...

oracle 執行儲存過程 ora 0131

今天一開發同事反應新建的測試使用者無法執行儲存過程,使用plsq遠端連線執行儲存過程報錯如下 報錯資訊是 ora 0131 insufficient privileges,就是使用者沒有儲存過程的除錯執行許可權 debug connect session 需要具有dba許可權的使用者登入授權即可 c...

Oracle儲存過程跨使用者執行查詢報錯

在oracle 中,在usera下編寫乙個儲存過程,該儲存過程中引用了另乙個使用者userb下的表或檢視物件。編譯該儲存過程,出現編譯錯誤。報ora 00942 table or view does not exist。但是該錶或檢視的確在userb下存在,而且已經授予了usera dba角色的許可...