在總結PL/SQL的基礎知識時,說到了以下內容:
[declare]
-- declaration statements
i integer;begin
-- executable statements
[exception]
-- exception statements
end;
對於其中的exception
沒有進行詳細的總結,那麼exception
在Oracle又是怎麼樣的呢?出現了exception
又要如何處理呢?這篇文章就對Oracle中的exception進行詳細的總結。
在Oracle中,異常分為以下兩類:
在Oracle中預定義的異常如下表所示:
異常名稱
錯誤代碼
產生原因
ACCESS_INTO_NULL
06530
為一個未初始化對象的屬性賦值
CASE_NOT_FOUND
06592
在CASE過程中,WHEN後沒有包含必要的條件分支並且沒有ELSE子句
COLLECTION_IS_NULL
06531
使用未初始化的集合元素
CURSOR_ALREADY_OPEN
06511
游標已經打開
DUP_VAL_ON_INDEX
00001
在具有唯一索引的列上插入一個重復值
INVALID_CURSOR
01001
在無效的游標上進行操作
INVALID_NUMBER
01722
在一個SQL語句中,由於字符串並不代表一個有效的數字,導致字符串向數字轉換時會發生錯誤。(在過程化語句中,會拋出異常VALUE_ERROR。)當FETCH語句的LIMIT子句表達式後面不是一個正數時,這個異常也會被拋出。
LOGIN_DENIED
01017
使用錯誤的用戶名或密碼登陸數據庫
NO_DATA_FOUND
01403
SELECT INTO未返回行,或者程序引用了嵌套表中一個已經刪除的元素,或者引用表中一個為初始化的元素
NOT_LOGGED_ON
01012
沒有連接到數據庫
PROGRAM_ERROR
06501
PL/SQL內部錯誤
ROWTYPE_MISMATCH
06504
賦值語句中使用的主游標變量和PL/SQL游標變量的類型不兼容
SELF_IS_NULL
30625
調用一個未被實例化的對象的成員方法,內置的SELF參數總是指向這個對象,SELF會作為函數的第一個參數傳遞到這個成員方法,就好比C++中的this
STORAGE_ERROR
06500
內存溢出或者內存不足
SUBSCRIPT_BEYOND_COUNT
06533
程序引用一個嵌套表或變長數組元素,但使用的下標索引超過嵌套表或變長數組元素總個數
SUBSCRIPT_OUTSIDE_LIMIT
06532
程序引用一個嵌套表或變長數組,但使用的下標索引不在合法的范圍內
SYS_INVALID_ROWID
01410
從字符串向ROWID轉換發生錯誤,因為字符串並不代表一個有效的ROWID
TIMEOUT_ON_RESOURCE
00051
當Oracle請求資源時,發生超時現象
TOO_MANY_ROWS
01422
SELECT INTO返回的行數太多
VALUE_ERROR
06502
發生算術、轉換、截位或長度約束錯誤。例如,當我們的程序把一個字段的值放到一個字符變量中時,如果值的長度大於變量的長度,PL/SQL就會終止賦值操作並拋出異常VALUE_ERROR。在過程化語句中,如果字符串向數字轉換失敗,異常VALUE_ERROR就會被拋出(在SQL語句中,異常INVALID_NUMBER會被拋出)
ZERO_DIVIDE
01476
程序嘗試除以0
和其它語言一樣,我們也可以定義我們滿足我們自己要求的異常,自定義一樣的語法格式如下:
PRAGMA EXCEPTION_INIT(exception_name, -Oracle_error_number);
定義了那麼多異常,那麼在程序中如何拋出異常呢?在Oracle中有以下三種方式觸發異常:
RAISE
語句手工觸發RAISE_APPLICATION_ERROR
手工觸發下面的代碼將演示Oracle自動觸發異常:
-- Created on 2015-7-14 by JellyThink
declare
iA NUMBER(2) := 10;begin
iA := iA / 0; -- Oracle自動觸發異常
dbms_output.put_line(iA);
exception
when ZERO_DIVIDE then
dbms_output.put_line('Error Code:' || SQLCODE || ' ' || SQLERRM);
when others then
dbms_output.put_line('Others Exception');end;
下面的代碼將演示使用RAISE
語句手工觸發異常:
-- Created on 2015-7-14 by JellyThink
declare
myException EXCEPTION;begin
RAISE myException; -- RAISE手工觸發異常
exception
when others then
dbms_output.put_line('Others Exception');end;
下面的代碼將演示使用RAISE_APPLICATION_ERROR
觸發異常:
-- Created on 2015-7-14 by JellyThink
declare
myException EXCEPTION;
PRAGMA EXCEPTION_INIT(myException, -20009);begin
RAISE_APPLICATION_ERROR(-20009, 'Exception'); -- 這裡可以指定異常信息
exception
when myException then
dbms_output.put_line('myException Exception');end;
先來看看下面這段代碼:
-- Created on 2015-7-15 by JellyThink
declare
i Number;begin
i := 10;
declare
begin
i := i / 0; -- 嵌套塊中拋出異常
/*exception
when ZERO_DIVIDE then
dbms_output.put_line('Error');*/ -- 嵌套塊不處理這個異常
end;
exception
-- 在這裡處理子塊拋出的異常
when ZERO_DIVIDE then
dbms_output.put_line('Error Code:' || SQLCODE || ' ' || SQLERRM);
when others then
dbms_output.put_line('Error Code:' || SQLCODE || ' ' || SQLERRM);end;
在一個塊中,只能有一個異常處理部分,在不同的塊中,可以定義多個異常處理部分。父塊中可以定義異常處理,子塊中也可以定義自己的異常處理。當一個子塊的異常發生時,如果在子塊的異常處理部分沒有進行處理,該異常會傳遞到父塊中,如果父塊中沒有對應的異常處理部分,那麼這個異常會繼續向上傳遞。
異常的處理在一個程序中是必不可少的,也是你的代碼走向完美的一個必要的部分。只有熟悉的掌握了異常處理,才能更好的服務於你的代碼。想想我們現在系統中的存儲過程,都沒有異常處理,哦,誰寫的,我保證不打死你。