Oracle系列之四——异常处理
Oracle系列之四——异常处理
为什么使用异常处理?每个程序员都知道的答案。Pl/sql也不例外,为了提高程序的健壮性,开发人员必须对相应的异常进行处理。
不过在oracle中,一般不叫异常,而是叫例外。
Oracle提供了预定义例外、非预定义例外、自定义例外三种类型。其中,预定义例外用于处理常见的Oracle错误;非预定义例外则用于处理预定义例外所不能处理的ORACLE错误;自定义例外则用于处理与ORACLE错误无关的其他情况。
开发人员应该在可能发生例外的地方捕捉例外,如果没有捕捉到,例外则会传递到调用环境。
在PL/SQL块中捕捉并处理例外需要使用例外处理部分来完成,例外处理部分是以关键字EXCEPTION开始的,语法如下:
Exception
When exception1 [ or exception2 ]then
Statement1;
Statement2;
When exception3 [ or exception4 ] then
Statement1;
Statement2;
…
When others then
Statement1;
如上,例外处理程序以EXCEPTION开始,在例外处理部分用WHEN子句来捕捉各种例外,如果还有其它预计不到的例外,可以使用when others子名来进行捕捉和处理。
-
处理预定义例外。
预定义例外是PL/SQL所提供的系统例外。当PL/SQL应用程序违反了ORACLE规则或系统限制时,则会隐含地触发一个内部例外。每个预定义例外都对应一种ORACLE系统错误。Oracle一共提供了二十多种预定义例外,我们可以在官方文档中找到这些预定义异常。
示例如下:
--例外示例
declare
v_name emp.ename%type;
begin
select ename into v_name from emp where empno = &no;
dbms_output.put_line('name:'|| v_name);
--异常处理块开始
exception
--捕捉特定异常
when no_data_found then
--针对特定异常进行处理
dbms_output.put_line('没有此雇员号,请检查输入是否正确。');
end;
-
处理非预定义例外
使用预定义例外只能处理22个ORACLE错误,而在开发pl/sql程序时,可能还会遇到其他Oracle错误,如在PL/SQL地中执行DML操作时,如果违反了约束规则,则会直接将错误传递到调用环境。
我们应该在程序中合理处理这些ORACLE错误。此时就需要非预定义例外,步骤如下:
首先在定义部分定义例外名,然后在ORACLE错误和例外名之间建立关联,最终在例外处理部分引用例外。当在关联例外名和ORACLE错误时,需要使用伪过程EXCEPTION_INIT.
示例如下:
--处理非预定义例外
declare
--定义例外名
e_demo exception;
--关联例外名和错误代码
pragma exception_init(e_demo,-2291);
begin
--dbms_output.put_line('========');
update emp set deptno=&dno where empno = &no;
--insert into dept values(13,'data',systimestamp);
--例外处理块
exception
when e_demo then
dbms_output.put_line('该员工不存在');
end;
我们在上面的例子中输入14和7499,因为dept与emp表之间具有主外键关系,所以在当在emp中修改员工的部门号时,该部门号必须在dept表中存在。如果不存在,则会抛出-2291错误。我们在这里将错误号-2291与例外e_demo进行关联,这样,当出现错误号为-2291的异常时,就会触发ora-0291对应的例外e_demo.
三.自定义异常
自定义例外是指PL/SQL开发人员定义的例外。预定义例外与非预定义例外都与ORACLE有关,并且当出现ORACLE错误时,会隐含地触发相应例外;而自定义例外与ORACLE错误没有任何关系,它是由开发人员为特定情况所定义的例外。
--处理非预定义例外
declare
--定义例外名
e_demo exception;
--关联例外名和错误代码
pragma exception_init(e_demo,-2291);
begin
--dbms_output.put_line('========');
update emp set deptno=&dno where empno = &no;
--insert into dept values(13,'data',systimestamp);
--例外处理块
exception
when e_demo then
dbms_output.put_line('该员工不存在');
end;
这段代码和上面的代码是完全相同的,但是当我们输入20和1111时,尽管员工号不存在1111,但是却不会出现任何错误。而这时,我们应该向用户显示更有意义的信息。这时就需要自定义异常。步骤如下:
首先在定义部分定义例外名,然后在出现例外进用RAISE子句显式的触发例外,最后在例外处理部分处理例外。
示例如下:
--处理非预定义例外
declare
--定义例外名
e_demo exception;
--关联例外名和错误代码
--pragma exception_init(e_demo, -2291);
begin
--dbms_output.put_line('========');
update emp set deptno = &dno where empno = &no;
if sql%notfound then
raise e_demo;
end if;
--insert into dept values(13,'data',systimestamp);
--例外处理块
exception
when e_demo then
dbms_output.put_line('该员工不存在');
end;
我们在原来的代码上稍加修改即可。此时再输入20和1111,就会打印出'该员工不存在'。
四.例外函数
熟悉JAVA的开发人员都知道,我们通过e.getMessage()可以获得异常的相关信息。对象e上定义了很多有价值的方法。同样的,我们在pl/sql中,我们也可以通过相关函数,获得例外的一些信息。比如SQLCODE可以获得错误号,SQLERRM可以获得错误号对应的错误信息,raise_application_error可以允许用户自定义错误号和错误信息。
--sqlcode和sqlerrm函数示例
declare
v_name emp.ename%type;
begin
select ename into v_name from emp;
exception
when no_data_found then
dbms_output.put_line('不存在雇员');
when others then
--在when others中特别有用
dbms_output.put_line('error code :'|| sqlcode);
dbms_output.put_line('error message :'|| sqlerrm);
end;
raise_application_error的语法如下:
raise_application_error(error_code,error_message[ , { true | false } ] );
其中,error_code用于定义错误号,该错误号只能是从-20000到-20999之间的负整数;
Error_message用于指定错误信息,并且该消息的长度不能超过2048字节;第三个参数可选,如果为true,则表示该错误会被放在先前的错误堆栈中;否则,则会替换先前所有错误。
注意,该过程只能在数据库端的子程序(过程、函数、包、触发器)中使用
而不能在匿名块和客户端的子程序中使用。