Oracle異常處理異常處理是考驗一個(gè)應用程序健壯性的最好方式,開(kāi)發(fā)人員必須考慮程序中可能出現的各種錯誤,并進(jìn)行相應的處理。
Oracle中異常分為:1.預定義異常2.非預定義異常3.自定義異常三種。
一、預定義異常預定義異常是指由PL/SQL所提供的系統異常。當PL/SQL應用程序違反了Oracle規則或出現其它系統限制的情況時(shí),將會(huì )隱含地觸發(fā)一個(gè)內部異常。以下是PL/SQL為我們預定義的異常(經(jīng)常更新中):
1.CURSOR_ALREADY_OPEN(cursor_already_open)該異常觸發(fā)ORA-06511錯誤。
當程序中的一個(gè)游標已經(jīng)執行了打開(kāi)操作,如果開(kāi)發(fā)人員試圖再一次打開(kāi)這個(gè)已經(jīng)打開(kāi)的游標時(shí),將觸發(fā)該異常。
示例:
DECLARE
CURSOR test_cursor IS
SELECT SYSDATE FROM dual;
BEGIN
OPEN test_cursor;
FOR test_cursor2 IN test_cursor LOOP
dbms_output.put_line(test_cursor2.SYSDATE);
END LOOP;
EXCEPTION
WHEN cursor_already_open THEN
dbms_output.put_line('游標已經(jīng)打開(kāi),不能再次對游標執行打開(kāi)操作。');
END;
/
2. INCALID_CURSOR(incalid_cursor)該異常觸發(fā)ORA-01001錯誤。
當試圖對一個(gè)尚未打開(kāi)的游標執行任何操作,如打開(kāi)該非法的游標執行賦值操作,或者關(guān)閉未打開(kāi)的游標時(shí),將觸發(fā)該異常。
示例:
DECLARE
CURSOR test_cursor IS
SELECT SYSDATE FROM dual;
test_time DATE;
BEGIN
--OPEN test_cursor;
FETCH test_cursor
INTO test_time;
dbms_output.put_line('當前時(shí)間為: ' || test_time);
CLOSE test_cursor;
EXCEPTION
WHEN invalid_cursor THEN
dbms_output.put_line('請檢查游標是否已經(jīng)打開(kāi).');
END;
/
3.NO_DATA_FOUND(no_data_found)該異常觸發(fā)ORA-01403錯誤。
當讀取一個(gè)游標進(jìn)行賦值操作(SELECT INTO操作)時(shí),如果未返回任何行,將觸發(fā)該異常。
示例:
DECLARE
test_owner DATE;
BEGIN
SELECT t.owner INTO test_owner FROM all_tables t WHERE t.table_name = 'test';
dbms_output.put_line(test_owner);
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('No value.');
END;
/
4. TOO_MANY_ROWS(too_many_rows)該異常觸發(fā)ORA-01422錯誤。
上面是沒(méi)有返回記錄,這里是返回對條記錄的時(shí)候會(huì )觸發(fā)該異常。
示例:
DECLARE
test_records dba_tables%ROWTYPE;
BEGIN
select * INTO test_records from dba_tables where owner='APPS' AND ROWNUM < 3;
dbms_output.put_line(test_records.table_name);
EXCEPTION
WHEN too_many_rows THEN
dbms_output.put_line('Too many values.');
END;
/
5. VALUE_ERROR(value_error)該異常觸發(fā)ORA-06502錯誤。
當在PL/SQL程序中執行賦值操作時(shí),如果右邊值的長(cháng)度大于左邊變量的長(cháng)度,將觸發(fā)該異常。
示例:
DECLARE
v_test VARCHAR2(1);
BEGIN
SELECT 'WHAT' INTO v_test FROM dual;
dbms_output.put_line(v_test);
EXCEPTION
WHEN value_error THEN
dbms_output.put_line('變量的長(cháng)度不夠.');
END;
/
6.DUP_VAL_ON_INDEX(dup_val_on_index)該異常觸發(fā)ORA-00001錯誤。
若表的每一列聲明為主鍵,或具有惟一性,如果對該列插入重復的值時(shí)將觸發(fā)該異常。
示例:
CREATE TABLE test_table
(
v_id NUMBER PRIMARY KEY,
v_name VARCHAR2(20)
)
INSERT INTO test_table VALUES(1,'test1');
INSERT INTO test_table VALUES(2,'test2');
SELECT * FROM test_table;
BEGIN
UPDATE test_table SET v_name = new_name WHERE v_id = &input_id;
EXCEPTION
WHEN dup_val_on_index THEN
dbms_output.put_line('在deptno列上不能出現重復值.');
END;
/
7. CASE_NOT_FOUND(case_not_found)該異常觸發(fā)ORA-06592錯誤。
在CASE語(yǔ)句中,如果CASE語(yǔ)句的條件在WHEN子句中沒(méi)有找到對應的條件分支,且該CASE語(yǔ)句不包含ELSE分支,將觸發(fā)該異常。
示例:
DECLARE
v_test NUMBER;
BEGIN
SELECT val INTO v_test FROM dual;
CASE
WHEN v_test = 1 THEN
dbms_output.put_line(v_test);
WHEN v_test = 2 THEN
dbms_output.put_line(v_test);
WHEN v_test = 3 THEN
dbms_output.put_line(v_test);
--ELSE
-- dbms_output.put_line(v_test);
END CASE;
EXCEPTION
WHEN case_not_found THEN
dbms_output.put_line('在CASE語(yǔ)句中沒(méi)有與' || v_test || '相關(guān)的條件.');
END;
/
8.ZERO_DIVIDE(zero_divide)該異常觸發(fā)ORA-01476錯誤。
當在程序中使用0作為除數進(jìn)行運算時(shí),將觸發(fā)該異常。
示例:
DECLARE
v_test1 NUMBER := 100;
v_test2 NUMBER := 0;
v_test3 NUMBER := 0;
BEGIN
v_test3 := v_test1 / v_test2;
dbms_output.put_line(v_test3);
EXCEPTION
WHEN zero_divide THEN
dbms_output.put_line('0不能作為除數.');
END;
/
9. INVALID_NUMBER(invalid_number)該異常觸發(fā)ORA-01722錯誤。
數字或值錯誤,或字符到數值的轉換錯誤。
示例:
BEGIN
UPDATE emp SET sal = sal + '1oo'; -- 1oo
EXCEPTION
WHEN invalid_number THEN
dbms_output.put_line('輸入的數字不正確.');
END;
/
DECLARE
v_test NUMBER;
v_test2 NUMBER;
BEGIN
v_test := '100';
v_test2 := '1a';
dbms_output.put_line(v_test);
EXCEPTION
WHEN INVALID_NUMBER THEN
DBMS_OUTPUT.PUT_LINE('輸入的數字不正確.');
END;
/
10. ACCESS_INTO_NULL(access_into_null)該異常觸發(fā)ORA-06530錯誤。
當程序中的對象還沒(méi)有先進(jìn)行對象初始化的操作,就直接為對象的屬性賦值,將觸發(fā)該異常。
示例:
DECLARE
v_test test_type;
BEGIN
v_test.v_name := 'test';
EXCEPTION
WHEN access_into_null THEN
dbms_output.put_line('首先初始化對象v_test');
END;
/
11. COLLECTION IS NULL(collection is null)該異常觸發(fā)ORA-06531錯誤。
在給集合元素賦值前,必須先初始化該集合元素,否則觸發(fā)該異常。
示例:
DECLARE
TYPE emp_ssn_array IS TABLE OF NUMBER/* INDEX BY BINARY_INTEGER*/;
best_employees emp_ssn_array;
BEGIN
best_employees(0) := '123456';
dbms_output.put_line('best_employees(0): ' || best_employees(0));
EXCEPTION
WHEN collection_is_null THEN
dbms_output.put_line('必須初始化集合元素.');
END;
/
12. SUBSCRIPT_BEYOND_COUNT(subscript_beyond_count)該異常觸發(fā)ORA-06533錯誤。
當使用復合數據類(lèi)型時(shí),如果下標越界觸發(fā)該異常。
示例:
DECLARE
TYPE test_array IS VARRAY(20) OF NUMBER;
v_test test_array;
BEGIN
v_test := test_array(123456);
dbms_output.put_line('v_test(1): ' || v_test(2));
EXCEPTION
WHEN subscript_beyond_count THEN
dbms_output.put_line('下標越界.');
END;
/
13.SUBSCRIPT_OUTSIDE_LIMIT(subscript_outside_limit)該異常觸發(fā)ORA-06532錯誤
當使用復合數據類(lèi)型時(shí),如果下標為負值時(shí)觸發(fā)該異常。
示例:
DECLARE
TYPE test_array IS VARRAY(20) OF NUMBER;
v_test test_array;
BEGIN
v_test := test_array(123456);
dbms_output.put_line('v_test(-1): ' || v_test(-1));
EXCEPTION
WHEN subscript_outside_limit THEN
dbms_output.put_line('下標不能是負數.');
END;
/
14.LONIN_DENIED該異常觸發(fā)ORA_01017錯誤。
當PL/SQL連接數據庫時(shí),如果密碼錯誤,將觸發(fā)該異常。
15. NOT_LOGGED_ON該異常觸發(fā)ORA-01012錯誤。
如果PL/SQL沒(méi)有連接數據庫,程序運行將觸發(fā)該異常。
16 PROGRAM_ERROR該異常觸發(fā)ORA-06501錯誤。
如果出現該異常,則表示PL/SQL的內部問(wèn)題。用戶(hù)可能需要重新安裝數據字典和PL/SQL系統包。
17 ROWTYPE MISMATCH該異常觸發(fā)ORA-06504錯誤。
在賦值時(shí),如果宿主游標變量和PL/SQL游標變量的返回類(lèi)型不兼容,將觸發(fā)該異常。
18 SELF_IF_NULL該異常觸發(fā)ORA-30625錯誤。
在使用對象類(lèi)型時(shí),如果在NULL示例上調用成員方法將觸發(fā)該異常。
19 STORAGE_ERROR該異常觸發(fā)ORA-06500錯誤。
當PL/SQL塊運行時(shí),如果走出內在空間或內在被損壞則觸發(fā)該異常。
20 SYS_INVALID_ROWID該異常觸發(fā)ORA-01410錯誤。
當將字符串轉變?yōu)镽OWID時(shí),如果使用了無(wú)效的字符串則觸發(fā)該異常。
21 TIMEOUT_ON_RESOURCE該異常觸發(fā)ORA-00051錯誤。
Oracle在等待資源時(shí)出現超時(shí)錯誤時(shí)將觸發(fā)該異常。
22 ORA-04021Oracle在等待資源時(shí)出現超時(shí)錯誤,該資源可能被其它session鎖住,此時(shí)將觸發(fā)該異常。
23 ORA-01791 不是Selected表達式SELECT DISTINCT goodsid,
barcode,
depotid,
goodsname
FROM sa_sale
WHERE depotid = '11'
ORDER BY selldate
這句話(huà)執行的時(shí)候就有錯誤, 但把排序換成order by Goodsid 或其它Barcode,DepotId,GoodsName的時(shí)候均沒(méi)有錯誤,這是因為selldate不在查詢(xún)結果字段中,而且這個(gè)語(yǔ)句是distinct語(yǔ)句。所以會(huì )出現這個(gè)錯誤
下邊給出正確的解決辦法:
SELECT goodsid,
barcode,
depotid,
goodsname
FROM (SELECT DISTINCT goodsid,
barcode,
depotid,
goodsname,
selldate
FROM sa_sale
WHERE depotid = '11')
ORDER BY selldate
24 ORA-01002: fetch out of sequence當游標中數據集已經(jīng)取完,然后再一次進(jìn)行FETCH操作時(shí)將觸發(fā)該異常。
25 PLS-00382: expression is of wrong type表達式類(lèi)型錯誤。即在代碼中賦予操作的左右兩邊的類(lèi)型不等。
二 非預定義異常使用非預定義異常的步驟如下:
定義異常-> 關(guān)聯(lián)異常和錯誤-> 引用例外
當定義Oracle錯誤和例外之間的關(guān)聯(lián)關(guān)系時(shí),要使用偽過(guò)程EXCEPTION_INTI。
下面以處理ORA-02291錯誤為例說(shuō)明:
DECLARE
e_integrity EXCEPTION;
PRAGMA EXCEPTION_INIT(e_integrity, -2291);
BEGIN
UPDATE emp SET deptno = dno WHERE empno = &eno;
EXCEPTION
WHEN e_integrity THEN
dbms_output.put_line('該部門(mén)不存在.');
END;
/
三 自定義異常使用預定義異常和非預定義異常,程序可以捕獲Oracle錯誤,并且在出現Oracle錯誤時(shí)自動(dòng)觸發(fā)對應的異常。但是在實(shí)際應用中,可能還會(huì )遇到其它錯誤,這時(shí),可以為特定的情況自定義異常,不過(guò)需要顯示觸發(fā)該異常:通過(guò)定義異常,然后關(guān)聯(lián)異常和錯誤,顯示觸發(fā)異常,最后在EXCEPTION中處理該異常。
示例:
DECLARE
l_error_message VARCHAR2(200);
e_user_exception EXCEPTION;
BEGIN
** ** ** ** **;
IF '出現錯誤' THEN
l_error_message := '定義錯誤信息';
RAISE e_user_exception;
END IF;
EXCEPTION
WHEN e_user_exception THEN
raise_application_error(-20001, l_error_message);
END;
/
四 例外函數1 SQLCODE,SQLERRM在PL/SQL塊中出現Oracle錯誤時(shí),通過(guò)使用例外函數可以取得錯誤號以及相關(guān)的錯誤消息。
SQLCODE 返回Oracle錯誤號。
SQLERRM 返回錯誤號對應的錯誤消息。
示例:
DECLARE
v_ename emp.ename%TYPE;
BEGIN
SELECT ename INTO v_ename FROM emp WHERE sal = &v_sal;
dbms_output.put_line('雇員名:' || v_ename);
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('不存在工資為' || v_sal || '雇員');
WHEN OTHERS THEN
dbms_output.put_line('錯誤號' || SQLCODE);
dbms_output.put_line(SQLERRM);
END;
/
2 RAISE_APPLICATION_ERROR在存儲過(guò)程,函數和包中使用RAISE_APPLICATION_ERROR可以自定義錯誤號和消息。
raise_application_error:用于自定義錯誤消息(用于程序段中)
語(yǔ)法:
raise_application_error(error_number,message[,{TRUE | FALSE}]);
error_number : 錯誤號,范圍是: -20000 ~ -20999之間的負整數;
message : 錯誤消息,長(cháng)度不能超過(guò)2048字節;
第三個(gè)可靠選參數,如果TRUE,該錯誤會(huì )被放在先前錯誤堆棧中;如果FALSE(默認),則替換先前所有錯誤.
示例:
CREATE OR REPLACE PROCEDURE raise_comm
(
eno NUMBER,
commission NUMBER
) IS
v_comm emp.comm%TYPE;
BEGIN
SELECT comm INTO v_comm FROM emp WHERE emp = eno;
IF v_comm IS NULL THEN
raise_application_error(-20001, '該員工無(wú)補助.');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('該雇員不存在.');
END;
/
聯(lián)系客服