一、異常類型分類
類型 | 說明 | 示例 |
---|---|---|
內置預定義異常 | Oracle已命名異常(如NO_DATA_FOUND) | 查詢無數據時觸發 |
內置非預定義異常 | 未命名的Oracle錯誤(需用PRAGMA EXCEPTION_INIT關聯) | ORA-02290(違反檢查約束) |
自定義異常 | 用戶定義的業務邏輯異常 | 數據校驗失敗時手動拋出 |
二、異常處理語法
1. 基本結構
DECLARE-- 聲明自定義異常custom_exception EXCEPTION;-- 綁定錯誤代碼到非預定義異常PRAGMA EXCEPTION_INIT(custom_exception, -20001);
BEGIN-- 業務邏輯IF 條件 THENRAISE custom_exception; -- 手動拋出異常END IF;
EXCEPTIONWHEN custom_exception THENDBMS_OUTPUT.PUT_LINE('自定義異常觸發');WHEN NO_DATA_FOUND THENDBMS_OUTPUT.PUT_LINE('數據未找到');WHEN OTHERS THENDBMS_OUTPUT.PUT_LINE('錯誤代碼: ' || SQLCODE);DBMS_OUTPUT.PUT_LINE('錯誤信息: ' || SQLERRM);
END;
三、異常語法
1. 自定義異常
步驟說明:
①聲明異常:
DECLAREinvalid_salary EXCEPTION;
②關聯錯誤代碼(可選):
PRAGMA EXCEPTION_INIT(invalid_salary, -20001);
③拋出異常:
IF salary < 0 THENRAISE invalid_salary;
END IF;
④捕獲處理:
EXCEPTIONWHEN invalid_salary THENDBMS_OUTPUT.PUT_LINE('薪資不能為負數');
2. 內置異常處理
常用預定義異常:
NO_DATA_FOUND: SELECT未找到數據
TOO_MANY_ROWS: SELECT返回多行數據
ZERO_DIVIDE: 除數為零
DUP_VAL_ON_INDEX: 唯一索引沖突
-- 示例:
BEGINSELECT * INTO emp_rec FROM emp WHERE emp_id = 999;
EXCEPTIONWHEN NO_DATA_FOUND THENDBMS_OUTPUT.PUT_LINE('員工ID不存在');WHEN TOO_MANY_ROWS THENDBMS_OUTPUT.PUT_LINE('返回多行數據');
END;
3. 嵌套異常處理
結構示例:
DECLAREouter_exception EXCEPTION;
BEGIN<<inner_block>>DECLAREinner_exception EXCEPTION;BEGINRAISE inner_exception;EXCEPTIONWHEN inner_exception THENDBMS_OUTPUT.PUT_LINE('內部異常已處理');RAISE outer_exception; -- 拋出到外層END inner_block;
EXCEPTIONWHEN outer_exception THENDBMS_OUTPUT.PUT_LINE('外部捕獲到異常');
END;
詳細實例:
DECLARE-- 定義變量和異常v_employee_id employees.employee_id%TYPE := 100;v_salary employees.salary%TYPE;e_negative_salary EXCEPTION; -- 自定義異常:工資為負PRAGMA EXCEPTION_INIT(e_negative_salary, -20001); -- 綁定錯誤代碼
BEGIN-- 外層塊BEGIN -- 內層塊開始-- 嘗試獲取員工工資SELECT salary INTO v_salary FROM employees WHERE employee_id = v_employee_id;-- 模擬業務邏輯:檢查工資有效性IF v_salary < 0 THENRAISE_APPLICATION_ERROR(-20001, '工資不能為負數'); -- 觸發自定義異常END IF;DBMS_OUTPUT.PUT_LINE('內層塊:工資處理成功。');EXCEPTION -- 內層異常處理WHEN NO_DATA_FOUND THENDBMS_OUTPUT.PUT_LINE('內層塊:員工ID ' || v_employee_id || ' 不存在。');RAISE; -- 重新拋出到外層WHEN e_negative_salary THENDBMS_OUTPUT.PUT_LINE('內層塊:異常 - ' || SQLERRM);-- 此處可添加恢復邏輯,如設置默認工資v_salary := 0;DBMS_OUTPUT.PUT_LINE('內層塊:工資已重置為0。');END; -- 內層塊結束-- 外層業務邏輯(內層未異常終止時執行)DBMS_OUTPUT.PUT_LINE('外層塊:更新后工資為 ' || v_salary);EXCEPTION -- 外層異常處理WHEN NO_DATA_FOUND THENDBMS_OUTPUT.PUT_LINE('外層塊:錯誤 - 指定員工不存在。');WHEN OTHERS THENDBMS_OUTPUT.PUT_LINE('外層塊:未知錯誤 - ' || SQLERRM);ROLLBACK; -- 示例事務回滾
END;
嵌套結構:
- 內層塊: 處理具體數據庫操作(如查詢、業務驗證),捕獲NO_DATA_FOUND(預定義)和自定義異常。
- 外層塊: 處理內層未處理的異常,執行后續業務邏輯或全局錯誤處理。
異常傳播:
- 內層處理并解決: 如e_negative_salary異常被捕獲后重置工資,程序繼續執行外層代碼。
- 內層重新拋出: NO_DATA_FOUND在內層處理后通過RAISE傳遞到外層,觸發外層對應處理程序。
自定義異常:
- 使用RAISE_APPLICATION_ERROR拋出并關聯錯誤代碼,PRAGMA
EXCEPTION_INIT將自定義異常綁定到特定錯誤號。
事務控制:
- 外層異常處理中可包含ROLLBACK,確保數據一致性(根據實際業務需求調整)。
嵌套規則:
- 內部塊未處理的異常會自動傳遞到外層塊
- 使用RAISE可手動將異常傳遞到上層
四、其他處理
1. 錯誤日志記錄
EXCEPTIONWHEN OTHERS THENINSERT INTO error_log (code, message, time)VALUES (SQLCODE, SQLERRM, SYSDATE);COMMIT;RAISE; -- 繼續向上層傳遞異常
END;
2. 動態錯誤消息
RAISE_APPLICATION_ERROR(-20001, '訂單 ' || order_id || ' 狀態無效');
3. 異常傳播控制
BEGIN-- 業務邏輯
EXCEPTIONWHEN OTHERS THENIF SQLCODE = -2290 THENDBMS_OUTPUT.PUT_LINE('約束違反');ELSERAISE; -- 繼續傳播未明確處理的異常END IF;
END;
五、總結
優先級處理:
EXCEPTIONWHEN NO_DATA_FOUND THEN ... -- 特定異常在前WHEN OTHERS THEN ... -- 通用處理在后
事務控制:
BEGINSAVEPOINT sp1;-- DML操作
EXCEPTIONWHEN OTHERS THENROLLBACK TO sp1;RAISE;
END;
錯誤代碼規范:
- 自定義錯誤代碼范圍:-20000 到 -20999
- 統一錯誤消息格式
通過合理使用異常處理機制,可顯著提升Oracle程序的健壯性。建議在復雜業務邏輯中優先定義清晰的異常處理策略。