1、异常的优点
2、异常的分类
有两种类型的异常,一种为内部异常,一种为用户自定义异常,内部异常是执行期间返回到PL/SQL块的。用户自定义异常由开发者显示定义,在PL/SQL块中传递信息以控制对于应用的错误处理。
为每个ORACLE错误都有一个号码并且在PL/SQL中异常通过名字处理,ORACLE提供了预定义的内部异常。如SELECT INTO 语句不返回行时产生的ORACLE异常NO_DATA_FOUND。最常用的异常列举如下:
exception | oracle error | sqlcode value | condition |
no_data_found | ora-01403 | +100 | select into 语句没有符合条件的记录返回 |
too_mang_rows | ora-01422 | -1422 | select into 语句符合条件的记录有多条返回 |
dup_val_on_index | ora-00001 | -1 | 对于数据库表中的某一列,该列已经被限制为唯一索引,程序试图存储两个重复的值 |
value_error | ora-06502 | -6502 | 在转换字符类型,截取或长度受限时,会发生该异常,如一个字符分配给一个变量,而该变量声明的长度比该字符短,就会引发该异常 |
storage_error | ora-06500 | -6500 | 内存溢出 |
zero_divide | ora-01476 | -1476 | 除数为零 |
case_not_found | ora-06592 | -6530 | 对于选择case语句,没有与之相匹配的条件,同时,也没有else语句捕获其他的条件 |
cursor_already_open | ora-06511 | -6511 | 程序试图打开一个已经打开的游标 |
timeout_on_resource | ora-00051 | -51 | 系统在等待某一资源,时间超时 |
3、异常的抛出
由三种方式抛出异常
1. 通过PL/SQL运行时引擎
2. 使用RAISE语句
3. 调用RAISE_APPLICATION_ERROR存储过程
当数据库或PL/SQL在运行时发生错误时,一个异常被PL/SQL运行时引擎自动抛出。异常也可以通过RAISE语句抛出
RAISE exception_name;
显式抛出异常是程序员处理声明的异常的习惯用法,但RAISE不限于声明了的异常,它可以抛出任何任何异常。例如,你希望用TIMEOUT_ON_RESOURCE错误检测新的运行时异常处理器,你只需简单的在程序中使用下面的语句:
RAISE TIMEOUT_ON_RESOUCE;
RAISE_APPLICATION_ERROR内建函数用于抛出一个异常并给异常赋予一个错误号以及错误信息。自定义异常的缺省错误号是+1,缺省信 息是User_Defined_Exception。RAISE_APPLICATION_ERROR函数能够在pl/sql程序块的执行部分和异常部分 调用,显式抛出带特殊错误号的命名异常。
Raise_application_error(error_number,message[,true,false]))
错误号的范围是-20,000到-20,999。错误信息是文本字符串,最多为2048字节。TRUE和FALSE表示是添加(TRUE)进错误堆(ERROR STACK)还是覆盖(overwrite)错误堆(FALSE)。缺省情况下是FALSE。
如下代码所示:
IF product_not_found THEN
RAISE_APPLICATION_ERROR(-20123,'Invald product code' TRUE);
END IF;
4、异常的处理
PL/SQL程序块的异常部分包含了程序处理错误的代码,当异常被抛出时,一个异常陷阱就自动发生,程序控制离开执行部分转入异常部分,一旦程序进入异常部分就不能再回到同一块的执行部分。下面是异常部分的一般语法:
EXCEPTION
WHEN exception_name THEN
Code for handing exception_name
[WHEN another_exception THEN
Code for handing another_exception]
处理异常
END
如果要处理未命名的内部异常,必须使用OTHERS异常处理器或PRAGMA EXCEPTION_INIT 。PRAGMA由编译器控制,或者是对于编译器的注释。PRAGMA在编译时处理,而不是在运行时处理。EXCEPTION_INIT告诉编译器将异常名 与ORACLE错误码结合起来,这样可以通过名字引用任意的内部异常,并且可以通过名字为异常编写一适当的异常处理器。
在子程序中使用EXCEPTION_INIT的语法如下:
PRAGMA EXCEPTION_INIT(exception_name, -Oracle_error_number);
在该语法中,异常名是声明的异常,下例是其用法:
定义一个自定义异常A,然后用PRAGMA_EXCEPTION_INIT 将 异常 A 与 -1476 (除数为零)号系统内部异常进行帮定,当有出数为零的异常发生后,他就出发异常A。此时的A相当于 zero_divide 异常。
对于用户自定义异常,只能在PL/SQL块中的声明部分声明异常,异常的名字由EXCEPTION关键字引入:
reserved_loaned Exception
产生异常后,控制传给了子程序的异常部分,将异常转向各自异常控制块,必须在代码中使用如下的结构处理错误:
Exception
When exception1 then
Sequence of statements;
When exception2 then
Sequence of statements;
When others then
5、多个异常触发与捕捉的机制
看6个例子:
(1)普通的例子
输出:EXCEPTION A!
(2)
输出:OUT EXCEPTION B!
异常B触发之后,里层的代码都不会再执行,所以异常A不会触发。
(3)
输出:
IN EXCEPTION A!
OUT EXCEPTION B!
在异常A触发之后,异常B因为是在异常A触发的程序块的外层触发的,而异常A在内层也被处理了。所以B也会触发。也就是说,当异常出发之后,如果能及时处理,只能退出本层,不会退出上层。上一层后面的代码还会继续执行。但是,下一层的都不在执行。
(4)
输出:OUT EXCEPTION A!
这个有一点难理解。当异常A触发后,没有被马上处理,导致,在被处理之前,所有其他的代码都不会执行,后面的异常B不会被触发,直接到达了下一个Exception。继续处理异常A。
(5)
输出:OTHERS EXCEPTION!
异常C触发之后后边的代码不会执行。直接到Exception来处理异常。
(6)
输出:OTHERS EXCEPTION!
异常A触发之后,又出发了异常C而没有对异常C进行即时的处理。所以异常B不会触发,代码自动转到下面的Exception. 异常名 |
异常标题 |
异常号 |
ACCESS_INTO_NULL |
ORA-06530 |
-6530 |
CASE_NOT_FOUND |
ORA-06592 |
-6592 |
COLLECTION_IS_NULL |
ORA-06531 |
-6531 |
CURSOR_ALREADY_OPEN |
ORA-06511 |
-6511 |
DUP_VAL_ON_INDEX |
ORA-00001 |
-1 |
INVALID_CURSOR |
ORA-01001 |
-1001 |
INVALID_NUMBER |
ORA-01722 |
-1722 |
LOGIN_DENIED |
ORA-01017 |
-1017 |
NO_DATA_FOUND |
ORA-01403 |
-1403 |
NOT_LOGGED_ON |
ORA-01012 |
-1012 |
PROGRAM_ERROR |
ORA-06501 |
-6501 |
ROWTYPE_MISMATCH |
ORA-06504 |
-6504 |
SELF_IS_NULL |
ORA-30625 |
-30625 |
STORAGE_ERROR |
ORA-06500 |
-6500 |
SUBSCRIPT_BEYOND_COUNT |
ORA-06533 |
-6533 |
SUBSCRIPT_OUTSIDE_LIMIT |
ORA-06532 |
-6532 |
SYS_INVALID_ROWID |
ORA-01410 |
-1410 |
TIMEOUT_ON_RESOURCE |
ORA-00051 |
-51 |
TOO_MANY_ROWS |
ORA-01422 |
-1422 |
VALUE_ERROR |
ORA-06502 |
-6502 |
ZERO_DIVIDE |
ORA-01476 |
-1476 |
异常名 |
说明 |
ACCESS_INTO_NULL |
Your program attempts to assign values to the attributes of an uninitialized (atomically null) object. |
CASE_NOT_FOUND |
one of the choices in the WHEN clauses of a ASE tatement is selected, and there is no ELSE clause. |
COLLECTION_IS_NULL |
Your program attempts to apply collection methods other than EXISTS to an uninitialized (atomically null) nested table or varray, or the program attempts to assign values to the elements of an uninitialized nested table or varray. |
CURSOR_ALREADY_OPEN |
Your program attempts to open an alrea*** open cursor. A cursor must be closed before it can be reopened. A cursor FOR loop automatically opens the cursor to which it refers. So, your program cannot open that cursor inside the loop. |
DUP_VAL_ON_INDEX |
Your program attempts to store duplicate values in a database column that is constrained by a unique index. |
INVALID_CURSOR |
Your program attempts an illegal cursor operation such as closing an unopened cursor. |
INVALID_NUMBER |
In a SQL statement, the conversion of a character st*** into a number fails because the st*** does not represent a valid number. (In procedural statements, VALUE_ERROR is raised.) This exception is also raised when the LIMIT-clause expression in a bulk FETCH statement does not evaluate to a positive number. |
LOGIN_DENIED |
Your program attempts to log on to Oracle with an invalid username and/or password. |
NO_DATA_FOUND |
A SELECT INTO statement returns no rows, or your program references a deleted element in a nested table or an uninitialized element in an index-by table. SQL aggregate functions such as AVG and SUM always return a value or a null. So, a SELECT INTO statement that calls an aggregate function never raises NO_DATA_FOUND. The FETCH statement is expected to return no rows eventually, so when that happens, no exception is raised. |
NOT_LOGGED_ON |
Your program issues a database call without being connected to Oracle. |
PROGRAM_ERROR |
PL/SQL has an internal problem. |
ROWTYPE_MISMATCH |
The host cursor variable and PL/SQL cursor variable involved in an assignment have incompatible return types. For example, when an open host cursor variable is passed to a stored subprogram, the return types of the actual and formal parameters must be compatible. |
SELF_IS_NULL |
Your program attempts to call a MEMBER method on a null instance. That is, the built-in parameter SELF (which is always the first parameter passed to a MEMBER method) is null. |
STORAGE_ERROR |
PL/SQL runs out of memory or memory has been corrupted. |
SUBSCRIPT_BEYOND_COUNT |
Your program references a nested table or varray element using an index number larger than the number of elements in the collection. |
SUBSCRIPT_OUTSIDE_LIMIT |
Your program references a nested table or varray element using an index number (-1 for example) that is outside the legal range. |
SYS_INVALID_ROWID |
The conversion of a character st*** into a universal rowid fails because the character st*** does not represent a valid rowid. |
TIMEOUT_ON_RESOURCE |
A time-out occurs while Oracle is waiting for a resource. |
TOO_MANY_ROWS |
A SELECT INTO statement returns more than one row. |
VALUE_ERROR |
An arithmetic, conversion, truncation, or size-constraint error occurs. For example, when your program selects a column value into a character variable, if the value is longer than the declared length of the variable, PL/SQL aborts the assignment and raises VALUE_ERROR. In procedural statements, VALUE_ERROR is raised if the conversion of a character st*** into a number fails. (In SQL statements, INVALID_NUMBER is raised.) |
ZERO_DIVIDE |
Your program attempts to divide a number by zero. |