Oracle数据库之PL/SQL异常处理
Oracle数据库之PL/SQL异常处理
异常指的是在程序运行过程中发生的异常事件,通常是由硬件问题或者程序设计问题所导致的。
PL/SQL程序设计过程中,即使是写得最好的程序也可能会遇到错误或未预料到的事件。一个健壮的程序都应该能够正确处理各种异常情况,并尽可能从中恢复。
1. 异常处理
异常处理是用来处理正常执行过程中未预料的事件。PL/SQL程序块一旦产生异常而没有指出如何处理时,程序就会自动终止整个程序运行。
PL/SQL编程过程中,有三种类型的异常:
1.预定义异常
对这种异常情况的处理,无需在程序中定义,当PL/SQL程序违反Oracle规则或超越系统限制时隐式引发。
2.非预定义异常
其他标准的Oracle错误。对这种异常情况的处理,需要用户在程序中定义,然后由Oracle自动将其引发。
3.用户定义异常
程序执行过程中,出现编程人员认为的非正常情况。对这种异常情况的处理,需要用户在程序中定义,然后显式地在程序中将其引发。
异常处理通常放在PL/SQL程序的后部,语法结构为:
EXCEPTION WHEN { exception [ OR exception ]... | OTHERS } THEN statement [ statement ]...
2. 预定义的异常处理
常见预定义异常:
错误号 | 异常名称 | 说明 |
---|---|---|
ORA-00001 | DUP_VAL_ON_INDEX | 重复索引值,违反了唯一性限制,当在唯一索引所对应的列上键入重复值时触发 |
ORA-01001 | INVALID_CURSOR | 试图使用一个无效的游标 |
ORA-01012 | NOT_LOGGED_ON | 没有连接到ORACLE |
ORA-01017 | LOGIN_DENIED | 无效的用户名/口令 |
ORA-01403 | NO_DATA_FOUND | 没有找到数据时触发 |
ORA-01422 | TOO_MANY_ROWS | 返回多行 |
ORA-01722 | INVALID_NUMBER | 转换为数字失败时触发 |
ORA-06511 | CURSOR_ALREADY_OPEN | 试图打开一个已处于打开状态的游标 |
ORA-06592 | CASE_NOT_FOUND | 当case条件都不满足时触发 |
更多预定义异常见:http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/errors.htm#LNPLS00703
对预定义异常的处理,只需在PL/SQL块的异常处理部分,直接引用相应的异常情况名,并对其完成相应的异常错误处理即可。
示例1:
DECLARE stock_price NUMBER := 9.73; net_earnings NUMBER := 0; pe_ratio NUMBER; BEGIN pe_ratio := stock_price / net_earnings; DBMS_OUTPUT.PUT_LINE('运算结果 = ' || pe_ratio); EXCEPTION WHEN ZERO_DIVIDE THEN DBMS_OUTPUT.PUT_LINE('/ by zero'); pe_ratio := NULL; END;
运行结果:
/ by zero
为避免除0异常,可以采用如下示例2方式解决:
示例2:
DECLARE stock_price NUMBER := 9.73; net_earnings NUMBER := 0; pe_ratio NUMBER; BEGIN pe_ratio := CASE net_earnings WHEN 0 THEN NULL ELSE stock_price / net_earnings END; END;
示例3:
DECLARE default_number NUMBER := 0; BEGIN INSERT INTO t VALUES(TO_NUMBER('100.00', '9G999')); EXCEPTION WHEN INVALID_NUMBER THEN DBMS_OUTPUT.PUT_LINE('使用默认值替换非法数字'); INSERT INTO t VALUES(default_number); END;
运行结果:
使用默认值替换非法数字
3. 非预定义的异常处理
非预定义异常有错误号没有名字,处理的办法是:自己定义一个名字,绑定到错误号,捕获错误名。处理这类异常,首先必须对非预定义的Oracle异常进行定义。
如:
myexcp EXCEPTION;
然后使用EXCEPTION_INIT语句与标准的ORACLE错误联系起来,如:
PRAGMA EXCEPTION_INIT(myexcp,-02292);
说明:ORA-02292是违反完整性约束的错误代码。
示例:
DECLARE myexcp EXCEPTION; PRAGMA EXCEPTION_INIT(myexcp,-02292); dno scott.emp.deptno%TYPE; BEGIN dno := &dept_no; DELETE FROM scott.dept WHERE deptno=dno; EXCEPTION WHEN myexcp THEN DELETE FROM scott.emp WHERE deptno=dno; DELETE FROM scott.dept WHERE deptno=dno; END;
4. 用户定义异常处理
我们可以在任何PL/SQL匿名块,子程序或包的声明部分声明自己的异常。用户定义的异常是通过使用RAISE语句显式触发的。
一般用户定义异常的处理流程为:定义异常->抛出异常->捕获及处理异常。
示例:
DECLARE invalidCATEGORY EXCEPTION; -- 定义异常 category VARCHAR2(10); BEGIN category := '&Category'; IF category NOT IN ('附件','顶盖','备件') THEN RAISE invalidCATEGORY; -- 抛出异常 ELSE DBMS_OUTPUT.PUT_LINE('您输入的类别是'|| category); END IF; EXCEPTION WHEN invalidCATEGORY THEN -- 捕获及处理异常 DBMS_OUTPUT.PUT_LINE('无法识别该类别'); END;
我们可以调用RAISE_APPLICATION_ERROR过程引发并传播应用程序异常,这为应用程序提供了一种与ORACLE交互的方法。
RAISE_APPLICATION_ERROR过程可用于创建用户定义的错误信息,可以在可执行部分和异常处理部分使用,错误编号必须介于–20000 和–20999之间,错误消息的长度可长达2048个字节。
RAISE_APPLICATION_ERROR过程语法:
RAISE_APPLICATION_ERROR (error_code, message[, {TRUE | FALSE}]);
如果指定TRUE,PL/SQL把ERROR_CODE上的错误信息添加到堆栈的顶部。指定FALSE,PL/SQL替换ERROR_CODE错误堆栈,默认值为FALSE。
示例1:
DECLARE empno employees.employee_id%TYPE; no_such_row EXCEPTION; BEGIN empno := &empno; UPDATE employees SET salary = salary+100 WHERE id = empno; IF SQL%NOTFOUND THEN RAISE no_such_row; END IF; EXCEPTION WHEN no_such_row THEN RAISE_APPLICATION_ERROR(-20001, '没有待修改的行'); END;
示例2:
BEGIN UPDATE emp SET deptno=80 WHERE empno=1111; IF SQL%NOTFOUND THEN RAISE_APPLICATION_ERROR(-20001,'该雇员不存在!'); END IF; EXCEPTION WHEN OTHERS THEN dbms_output.put_line(SQLCODE||'-->'||SQLERRM); END;
SQLCODE用于取得Oracle错误号。
SQLERRM则用于取得与之相关的错误消息。