本章内容
异常概述
Oracle错误处理机制
异常的类型
Oracle错误处理机制
1、Oracle中对运行时错误的处理采用了异常处理机制。
2、一个错误对应一个异常,当错误产生时抛出相应的异常,并被异常处理器捕获,程序控制权传递给异常处理器,由异常处理器来处理运行时错误。
异常的类型
预定义的Oracle异常
异常情况名 | 错误代码 | 描述 |
CURSOR_ALREADY_OPEN | ORA-06511 | 尝试打开已经打开的游标 |
INVALID_CURSOR | ORA-01001 | 不合法的游标操作(如要打开已经关闭的游标) |
NO_DATA_FOUND | ORA-01403 | 没有发现数据 |
TOO_MANY_ROWS | ORA-01422 | 一个SELECT INTO语句匹配多个数据行 |
INVALID_NUMBER | ORA-01722 | 转换成数字失败 (‘X’) |
VALUE_ERROR | ORA-06502 | 截断、算法或转换错误,通常出现在赋值错误 |
ZERO_DIVIDE | ORA-01476 | 除数为0 |
ROWTYPE_MISMATCH | ORA-06504 | 主机游标变量与PL/SQL游标变量类型不匹配 |
异常情况名 | 错误代码 | 描述 |
DUP_VAL_ON_INDEX | ORA-00001 | 违反唯一性约束或主键约束 |
SYS_INVALID_ROWID | ORA-01410 | 转换成ROWID失败 |
TIMEOUT_ON_RESOURCE | ORA-00051 | 在等待资源中出现超时 |
LOGIN_DENIED | ORA-01017 | 无效用户名/密码 |
CASE_NOT_FOUND | ORA-06592 | 没有匹配的WHEN子句 |
NOT_LOGGED_ON | ORA-01012 | 没有与数据库建立连接 |
STORAGE_ERROR | ORA-06500 | PL/SQL内部错误 |
PROGRAM_ERROR | ORA-06501 | PL/SQL内部错误 |
异常情况名 | 错误代码 | 描述 |
ACCESS_INTO_NULL | ORA-06530 | 给空对象属性赋值 |
COLLECTION_IS_NULL | ORA-06531 | 对某NULL PL/SQL表或可变数组试图应用集合方法,而不是EXISTS |
SELF_IS_NULL | ORA-30625 | 调用空对象实例的方法 |
SUBSCRIPT_BEYOND_COUNT | ORA-06533 | 对嵌套表或数组索引引用时超出集合中元素的数量 |
SUBSCRIPT_OUTSIDE_LIMIT | ORA-06532 | 对嵌套表或可变数组索引的引用超出声明的范围 |
非预定义异常
• 声明一个异常名称e_integrity EXCEPTION;• 将异常与一个 Oracle 错误号相绑定PRAGMA EXCEPTION-INIT(e_integrity.-2291)• 示例DECLAREe_deptno_fk EXCEPTION;PRAGMA EXCEPTION_INIT(e_deptno_fk,-2292);BEGIN……EXCEPTION……END;
用户自定义的异常
异常处理过程
异常的定义
-20999~-20000为用户定义错误的保留号。
异常的抛出
异常的捕获与处理
注意 :一个异常处理器可以捕获多个异常,只需在 WHEN 子句中用OR连接即可;
一个异常只能被一个异常处理器捕获,并进行处理。
DECLARE
v_sal emp.sal%type;
BEGIN
SELECT sal INTO v_sal FROM emp WHERE ename='SMITH';
DBMS_OUTPUT.PUT_LINE(v_sal);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('There is not such an emplyee!');
WHEN TOO_MANY_ROWS THEN
FOR v_emp IN (SELECT * FROM emp WHERE ename='SMITH')
LOOP
DBMS_OUTPUT.PUT_LINE(v_emp.empno||' '||v_emp.sal);
END LOOP;
END;
DECLARE
e_deptno_fk EXCEPTION;
PRAGMA EXCEPTION_INIT(e_deptno_fk,-2292);
BEGIN
DELETE FROM dept WHERE deptno=10;
EXCEPTION
WHEN e_deptno_fk THEN
DBMS_OUTPUT.PUT_LINE(' There are subrecords in emp
table!');
END;
DECLARE
e_highlimit EXCEPTION;
v_sal emp.sal%TYPE;
BEGIN
UPDATE emp SET sal=sal+100 WHERE empno=7844 RETURNING sal INTO v_sal;
IF v_sal>6000 THEN
RAISE e_highlimit;
END IF;
EXCEPTION
WHEN e_highlimit THEN
DBMS_OUTPUT.PUT_LINE('The salary is too large!');
ROLLBACK;
END;
OTHERS异常处理器
DECLARE
v_sal emp.sal%TYPE;
e_highlimit EXCEPTION;
BEGIN
SELECT sal INTO v_sal FROM emp WHERE ename='JOAN';
UPDATE emp SET sal=sal+100 WHERE empno=7900;
IF v_sal>6000 THEN
RAISE e_highlimit;
END IF;
EXCEPTION
WHEN e_highlimit THEN
DBMS_OUTPUT.PUT_LINE('The salary is too large!');
ROLLBACK;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('There is some wrong in
selecting!');
END;
SQLCODE :返回当前错误代码。• 如果是用户定义错误返回值为 1 ;• 如果是 ORA-1403 : NO DATA FOUND 错误,返回值为 100• 其他 Oracle 内部错误返回相应的错误号。SQLERRM :返回当前错误的消息文本。• 如果是 Oracle 内部错误,返回系统内部的错误描述;• 如果是用户定义错误,则返回信息文本为“ User-defined Exception” 。
DECLARE
v_sal emp.sal%TYPE;
e_highlimit EXCEPTION;
v_code NUMBER(6);
v_text VARCHAR2(200);
BEGIN
SELECT sal INTO v_sal FROM emp WHERE ename='JOAN';
UPDATE emp SET sal=sal+100 WHERE empno=7900;
IF v_sal>6000 THEN
RAISE e_highlimit;
END IF;
EXCEPTION
WHEN e_highlimit THEN
DBMS_OUTPUT.PUT_LINE('The salary is too large!');
ROLLBACK;
WHEN OTHERS THEN
v_code:=SQLCODE;
v_text:=SQLERRM;
DBMS_OUTPUT.PUT_LINE(v_code||' '||v_text);
END;
异常的传播
执行部分异常的传播
DECLARE
v_sal emp.sal%TYPE;
BEGIN
BEGIN
SELECT sal INTO v_sal FROM emp WHERE ename='JOAN';
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('There is not such an employee!');
END;
DBMS_OUTPUT.PUT_LINE('Now this is outputted by outer
block!');
END;
/
There is not such an employee!
Now this is outputted by outer block!
DECLARE
v_sal emp.sal%TYPE;
BEGIN
BEGIN
SELECT sal INTO v_sal FROM emp WHERE deptno=10;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('There is not such an employee!');
END;
DBMS_OUTPUT.PUT_LINE('Now this is outputted by outer
block!');
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('There are more than one employee!');
END;
/
There are more than one employee!
声明部分和异常处理部分的异常
声明部分和异常处理部分的异常会立刻传播到外层语句块的异常处理部分,即使当前语句块有该异常的异常处理器。
BEGIN
DECLARE
v_number NUMBER(6) :='ABC';
BEGIN
v_number:=10;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('This is outputted by inner
block!');
END;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('This is outputted by outer
block!');
END;
/
This is outputted by outer block!