异常(EXCEPTION)情况处理是用来处理程序在运行从出现可预见或者不可预见的情况,它可以处理Oracle预定义的异常和用户自定义的错误。PLSQL块中一旦产生异常而没有做异常处理会自动终止程序。
异常的分类
- Oracle预定义异常,有异常名称,异常代码和错误原因,这类异常可以直接在异常处理中直接使用,。
- 非预定义异常,有错误代码和错误原因,但是没有异常名称,需要事先声明异常名称才可以使用。
- 自定义异常,用户可以自己声明异常的发生条件和名称,灵活使用。
语法
Oracle的异常处理和Java中的异常处理try catch非常的相似。
--异常处理以exception关键字开始,以end结束
begin
可执行代码;
exception
when 异常1 or 异常2 then
处理程序...
when 异常3 then
处理程序..
[when others then]
处理程序...
end;
预定义异常
常见的预定义异常
错误号 异常错误信息名称 说明
ORA-0001 Dup_val_on_index 违反了唯一性限制
ORA-0051 Timeout_on_resource 在等待资源时发生超时
ORA-0061 Transaction_backed_out 由于发生死锁事务被撤消
ORA-1001 Invalid-CURSOR 试图使用一个无效的游标
ORA-1012 Not_logged_on 没有连接到ORACLE
ORA-1017 Login_denied 无效的用户名/口令
ORA-1403 no_data_found SELECT INTO没有找到数据
ORA-1422 too_many_rows SELECT INTO 返回多行
ORA-1476 Zero_divide 试图被零除
ORA-1722 Invalid_NUMBER 转换一个数字失败
ORA-6500 Storage_error 内存不够引发的内部错误
ORA-6501 Program_error 内部错误
ORA-6502 Value_error 转换或截断错误
ORA-6504 Rowtype_mismatch 宿主游标变量与 PL/SQL变量有不兼容行类型
ORA-6511 CURSOR_already_OPEN 试图打开一个已处于打开状态的游标
ORA-6530 Access_INTO_null 试图为null 对象的属性赋值
ORA-6531 Collection_is_null 试图将Exists 以外的集合( collection)方法应用于一个null pl/sql 表上或varray上
ORA-6532 Subscript_outside_limit 对嵌套或varray索引得引用超出声明范围以外
ORA-6533 Subscript_beyond_count 对嵌套或varray 索引得引用大于集合中元素的个数.
示例
--no_data_found、too_many_rows,通过select into 给变量赋值时,容易报这两个错误
declare
v_id number;
begin
with
tab as(select 1 id from dual
union all
select 1 id from dual) --with tab as是预定义临时表
select id
into v_id --如果不做处理会报no_data_found这个错误
from tab
where id=3;
exception
when no_data_found then --Oracle预定义异常,直接直接根据名称使用
v_id := null;
dbms_output.put_line('no_data_found');
when too_many_rows then
v_id := null;
dbms_output.put_line('too_many_rows');
end;
declare
v_id number;
begin
with
tab as(select 1 id from dual
union all
select 1 id from dual)
select id
into v_id --如果不做处理会报too_many_rows错误
from tab
where id=3;
exception
when no_data_found then
v_id := null;
dbms_output.put_line('no_data_found');
when too_many_rows then
v_id := null;
dbms_output.put_line('too_many_rows');
end;
非预定义异常
针对非预定义的异常,可以定义一个异常,并与错误代码关联,就可以象预定义异常一样处理了
语法
--声明异常
异常名称 exception;
--异常代码绑定
异常名称 exception_init(异常名称,错误代码);
示例
--创建环境
create table gsc_test(id number(10),name varchar2(10));
alter table gsc_test modify name not null;
declare
null_value exception;
pragma exception_init(null_value,-01400);
begin
insert into gsc_test (id,name) values(1,null); --如果不处理会报ORA-01400: cannot insert NULL into错误
exception
when null_value then
dbms_output.put_line('插入空值');
end;
--注意,ORA-01031: insufficient privileges 这类权限校验的,没法预定义异常
自定义异常
语法
--抛出自定义异常,无需绑定异常代码
declare
异常名称 exception
begin
raise 异常名;--抛出异常
exception
when 异常名 then --处理异常
end;
--抛出预定义异常,无需声明异常
declare
begin
raise 预定义异常名;--抛出异常
exception
when 预定义异常名 then --处理异常
end;
--抛出非预定义异常,比较特殊,使用raise_application_error抛出异常
begin
raise_application_error(代码号,异常的明细);
--代码号的范围在-20000至-20999之间随意填写
end;
示例
--raise_application_error抛出的异常,可以用exception when others 来处理
declare
v_result number;
v_sqlerrm varchar2(4000);
begin
v_result := 0;
for i in 1..100
loop
v_result := v_result + i;
if v_result >=1000 then
raise_application_error(-20001,'超出范围啦'); --抛出非预定义异常
end if;
end loop;
exception when others then
v_sqlerrm := substrb(dbms_utility.format_error_backtrace||sqlerrm, 1, 4000);
--dbms_utility.format_error_backtrace是获取报错的行数,sqlerrm是报错的内容,也就是我们定义的'超出范围啦'。
--这段异常拼接语句非常常用,能够帮助我们快速了解出错的行数和报错信息。
dbms_output.put_line(v_sqlerrm);
end;
输出
ORA-06512: 在 line 11
ORA-20001: 超出范围啦