3.7.4 用户自定义的异常
除了Oracle定义的两种异常外,在PL/SQL中还可以自定义异常。程序员可以把一些特定的状态定义为异常。这样的异常一般由程序员自己决定,在一定的条件下抛出,然后利用PL/SQL的异常机制进行处理。
对于用户自定义的异常,有两种处理方法。第一种方法是先定义一个异常,并在适当的时候抛出,然后在PL/SQL块的异常处理部分进行处理。用户自定义的异常一般在一定的条件下抛出,于是这个条件就成为引发这个异常的原因;第二种方法是向调用者返回一个自定义的错误代码和一条错误信息。
这里先介绍第一种方法。异常的定义在PL/SQL块的声明部分进行,定义的格式为:
异常名称 EXCEPTION
异常名称这时仅仅是一个符号,仅当在一定条件下抛出时,这个异常才有意义。抛出异常的命令是RAISE,异常的抛出在PL/SQL块的可执行部分进行。RAISE命令的格式为:
RAISE 异常名称
异常一般在一定的条件下抛出,因此RAISE语句通常跟在某个条件判断的后面,这样就把这个异常与这个条件关联起来了。抛出异常的原因可能是数据出错,也可能是满足了某个自定义的条件,处理自定义异常的方法与处理前两种异常的方法相同。
例如,编写一个PL/SQL程序,求1+2+3+……100的值。在求和的过程中如果发现结果超出了1000,则抛出异常,并停止求和。这个块的代码如下:
DECLARE
out_of_range EXCEPTION;—定义异常
result integer:=0;
BEGIN
for i in 1..100 loop
result:=result+i;
if result>1000 then
RAISE out_of_range;—抛出异常
END if;
END loop;
EXCEPTION
WHEN out_of_range THEN—处理异常
dbms_output.put_line('当前的计算结果为'||result||',已超出范围');
END;
这个块的执行结果为:
当前的计算结果为1035,已超出范围
用RAISE命令不仅可以抛出一个自定义的异常,也可以抛出一个预定义异常和非预定义异常。例如,在上面求和的例子中,当计算结果超过1000时可以抛出异常VALUE_ERROR。修改后的PL/SQL块代码如下:
DECLARE
result integer:=0;
BEGIN
for i in 1..100 loop
result:=result+i;
if result>1000 then
RAISE VALUE_ERROR;—当条件满足时抛出一个预定义的异常
END if;
END loop;
EXCEPTION
WHEN VALUE_ERROR THEN
dbms_output.put_line('当前的计算结果为'||result||',已超出范围');
END;
这个块的执行结果为:
当前的计算结果为1035,已超出范围
现在再来介绍自定义异常处理的第二种方法。当PL/SQL块的执行满足一定的条件时,可以向PL/SQL程序返回一个错误代码和一条错误信息。错误代码的范围是-20000到-20999,这个范围的代码是Oracle保留的,本身没有任何意义。程序如果把一个错误代码与某个条件关联起来,那么在条件满足时系统将引发这样的错误。当然这是人为制造的一种错误,并不表示程序或数据真正出现了错误。
PL/SQL提供了一个过程,用于向PL/SQL程序返回一个一个错误代码和一条错误信息。这个过程是RAISE_APPLICATION_ERROR,过程的调用格式为:
RAISE_APPLICATION_ERROR(错误代码,错误信息)
例如,对上面求和的例子加以修改,当计算结果大于1000时,PL/SQL程序便得到一个错误代码-20001和一条错误信息。修改后的代码如下:
DECLARE
result integer:=0;
BEGIN
for i in 1..100 loop
result:=result+i;
if result>1000 then
RAISE_APPLICATION_ERROR(-20001,'当前的计算结果为'||result||',已超出范围');
END if;
END loop;
END;
这个块的执行结果为:
DECLARE
*
ERROR位于第1行:
ORA-20001:当前的计算结果为1035,已超出范围
ORA-06512:在line 7
从程序运行的结果来看,程序的执行过程确实发生了错误,返回了指定的错误代码和错误信息。在这一点上用户自定义的异常与非预定义异常是相似的。只不过非预定义异常是由数据库服务器自动抛出的,并且错误代码和错误信息都是由数据库服务器指定的,而用户自定义的异常是由程序员抛出的,错误代码和错误信息都是由程序员指定的。
在处理非预定义异常时,我们为每个错误代码指定了一个异常名称,然后就可以根据这个名称进行异常处理。既然用户自定义的异常也可以向调用者返回错误代码和错误信息,那么我们也可以采用同样的方法处理这样的异常。
首先定义一个异常,然后把这个异常与某个错误代码关联起来。这两步都在PL/SQL块的声明部分进行。然后在PL/SQL程序的可执行部分根据一定的条件,抛出这个异常。最后在PL/SQL块的异常处理部分捕捉并处理这个命名的异常。例如,用这种方法重新处理上述求和的例子中的异常,代码如下:
DECLARE
result integer:=0;
out_of_range EXCEPTION;
PRAGMA EXCEPTION_INIT(out_of_range,-20001);
BEGIN
for i in 1..100 loop
result:=result+i;
if result>1000 then
RAISE_APPLICATION_ERROR(-20001,'当前的计算结果为'||result||',已超出范围');
END if;
END loop;
EXCEPTION
WHEN out_of_range THEN
dbms_output.put_line('错误代码:'||SQLCODE);
dbms_output.put_line('错误信息:'||SQLERRM);
END;
这个块的执行结果为:
错误代码:-20001
错误信息:ORA-20001:当前的计算结果为1035,已超出范围
从上述PL/SQL块可以看出,我们首先在声明部分定义了一个异常out_of_range,然后把这个异常与错误代码-20001关联起来,一旦程序在运行过程中发生了这个错误,就是抛出了异常out_of_range。在块的可执行部分,如果在累加的过程中变量result的值超过了1000,则返回错误代码-20001以及相应的错误信息。这样在异常处理部分就可以捕捉并处理异常out_of_range了。
在处理用户自定义的异常时,也可以使用函数SQLCODE和SQLERRM,这两个函数分别用于返回指定的错误代码和错误信息。从程序的运行结果可以看出,这两个函数确实返回了指定的错误代码和错误信息。这样的错误代码和错误信息是在可执行部分通过过程RAISE_APPLICATION_ERROR指定的。