pl/sql
提供了强大而灵活的手段来捕捉和处理程序产生的异常,从而使
oracle
的用户远离一些令人烦恼的
bug
。
异常定义
在一个异常产生、被捕获并处理之前,它必须被定义。
Oracle
定义了几千个异常,绝大多数只有错误编号和相关描述,仅仅命名了若干个最常被用到的异常。这些名字被储存在
STANDARD
,
UTL_FILE
,
DBMS_SQL
这几个系统包中,详情请见
oracle:pl/sql
异常处理(
1
)。
出自之外的绝大多数异常需要程序员命名。有
2
种命名异常的方法:
1
:声明一个自定义异常
在
STANDARD
中的命名了的异常基本山是与系统的错误相关的(当然那些只有
errorcode
的异常也是这样),但在实际的应用中我们经常需要与特定的应用程序相关的异常,由程序员声明的异常就是用于处理这种情况的。
Oracle
异常处理模块的方便的地方在于,它并没有区别对待自定义的与预定义的异常。这使得我们可以像对待预定义异常一样,捕捉和处理自定义异常,只是在此之前需要声明它;同时对于一个自定义的异常,我们需要用
RAISE
来手动产生。
下面是一个声明的例子:
procedure calc_ammul_sales
(company_id_in in company.company_id%tye)
is
invalid_company_id exception;
negative_balance excrption;
duplicate_company Boolean;
begin
/*body of executable statement*/
exception
when invalid_company_id
then /*handle exception*/
when no_data_found
then /*handle exception*/
/*…..*/
end;
需要注意的是处理定义的时候,只有两个地方会出现自定义的异常:
ü
raise exception
;
ü
when exception then
2
:为非预定义异常关联一个名字
仅仅
21
个预定义异常对我们来说实在是太少了,还有几千个异常只有
errorcode
和描述。另外,程序员也可以用
RAISE_APPLICATION_ERROR
定义一个含
errorcode
和描述的异常。
当然,只用
errorcode
也可以很好地完成工作,只要你不担心会忘了那串数字代表的意思就行。比方说
;
exception
when others
then
if sqlcode=-1843 then /*sqlcode
是内建的用于返回最近一次错误编号的函数
*/
…..
这的确是一段让人感到晦涩的代码,还是给它关联个名字吧。
我们要用到的是
pragma exception_init(exception,integer)
,然后就可以像对待预定义异常一样对待它了,我是说没必要像上面的那种一样用
raise
。
Exception_init
是一个编译时运行的函数,它只能出现在代码的声明部分,而异常名字必须在此之前被定义。下面用一个匿名过程举个例子:
declare
invalid_company_id exception;
pragma exception_init(invalid_company_id, -1834);
要注意的时:
ü
不可以用
-1403
(
no_data_found
),用
100
,事实上
exception_init
中的
integer
对应的是
sqlcode
返回的值。
ü
不能为
0
,不能大于
100
,不能小于
-1000000
一个例子:
procedure delete_company(company_id_in in number)
is
still_have_emplyee exception;
pragma exception(still_have_employee, -2293);
begin
delete from compamy
where company_id=company_id_in;
exception
when still_have_employee
then dbms_output.put_line(‘delete employees for company first’);
end;
在一下两种情况下,我们有必要使用
exception_init
:
ü
一个非预定义异常是经常要被用到的。
ü
我们将用
raise_applocation_error
产生了一个自定义的
errorcode
时。
一种简便的方法是将以上两种情况中的异常定义在一个包中,这样我们就没有必要每次都重复定义了。
Create or replace package dynsql
Is
Invalid_table_name exception;
Pragma exception_init(invalid_table_name, -903);
Invalid_column_name exception;
Pragma exception_init(invalid_column_name, -904);
En_too_young const number:=-200001;
Exc_too_young exception;
Pragma exception_init(exc_too_young, -20001);
End;
有了上面这个包,就可以方便的处理异常了
;
procedure validate_emp(birthdate in date)
is
min_tear const pls_integer:=18;
begin
if add_month(sysdate,min_year*12*-1)<birthdate_in
then
raise_application_error(dynsql.en_too_young, ‘employee must be’ || min_year ||‘old’);
end if;
end;
除了
standard
包中的
21
个预定义异常外,还有一些包也定义了一些异常。但与
standard
包中异常不同的是,在使用这些异常时,需要带上包的名字。如:
when dbms_lob.invalid_argval then ……
非常有用的一点是,可以在最外层的
pl/sql
块的异常处理模块中加入
others
,这样就可以把从内部传递出来的未被处理的剩余异常全部处理掉了。
Exception
When others
Then ….