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 ….

Posted on 2006-10-25 16:23 艾凡赫 阅读(2686) 评论(0)  编辑 收藏 引用 所属分类: ORACLE

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理