Oracle Error Handling(Oracle 异常处理)

今天被企业导师要求在之前编写的存储过程中加入异常处理的语句, 以增强代码的健壮性.  研究了下 Oracle11g 官方文档, 再做一个简单的实践就解决了. 还是写个博客理理思路, 毕竟好记性不如烂笔头. 由于篇幅和时间关系, 这里只结合部分实例对Oracle的异常处理做一个大概的介绍,  想要完全完整学习Oracle异常处理请自行参阅 Oracle11g官方文档. 如果只是想快速上手异常处理, 不想看概念, 请直接查看本文实例.


一.Oracle支持三种类型的异常: 内部定义异常, 预定义异常 和 用户自定义异常


1.Internally Defined Exceptions:  内部定义异常

内部定义异常 是 Oracle 数据库异常信息集 中已经定义好了的异常信息,  由系统自行抛出( 隐式抛出 ). 这种类型的异常只拥有异常代码(error code 如ORA-27102 ), 没有异常名称, 除非我们给它一个名称 或 PL/SQL给它一个名称. 因此也被称为非预定义内部定义异常(这么叫的原因请看预定义异常概念).


2.Predefined Exceptions:  预定义异常

预定义异常其实就是拥有自己的异常名(error name)的内部定义异常, 所以其实是预定义内部定义异常. 比如 ORA-06500就拥有自己的名字 STORAGE_ERROR


3.User-Defined Exceptions: 自定义异常

自定义异常自然就是根据我们需要而定义的异常, 需要我们自己在代码中抛出(使用 raise 关键字, 显示抛出). 比如 我们规定 a < b是不合法的, 那么我们就可以使用一个if 语句来判断, 当 a < b的时候,就抛出我们自定义的异常, 并做处理.


二.错误信息的获取

在Oralce中, 我们可以使用SQLCODE 和 SQLERRM来获取错误代码 和 错误信息, 但是需要注意: 这两者都是过程化函数, 不能在SQL中直接使用, 只能将它们的返回值先赋给局部变量(如 mypara := sqlcode ), 再使用这些局部变量.


三.处理异常可以分为根据异常名来做针对性的处理只使用others 对异常做一个笼统的处理两种情况.


1) 使用异常名称做针对性处理 (可用于处理拥有异常名称的异常: 自定义异常, 预定义异常, 被给予了名称的内部定义异常)

注: 对于没有异常名的内部定义异常,  如果我们大概知道可能会抛出的异常,  并且知道异常的代码, 我们可以给予异常名称, 使用异常名称来做针对性的异常处理.

实例1: 定义名称为 my_exception 的自定义异常, 使用raise关键字抛出, 捕获后针对异常名做一个处理. 

-- author: csdn libertine1993
create or replace procedure pro_selfdefinde_exp 
as
  my_exception exception;                          --定义自定义异常名称
  para1 number := 1;
  para2 number := 2;
begin
  if para1 < para2 then                            --这里我们规定para1 < para2是不合法的, 使用raise抛出异常 my_exception
    raise my_exception;
  end if;
exception
  when my_exception then
  insert into my_error_info(f_id, f_error_msg)
  values(sys_guid(), '使用my_exception异常名, 捕获到了异常!');
end pro_selfdefinde_exp;

我们知道异常的名字是my_exception, 可以在捕获的时候做一些针对性的处理, 这里的针对性处理就是插入一条有针对性的描述的记录.于是我们可以看到下面这条记录




实例2:使用预定义异常的名字处理异常, 由于预定义异常属于内部定义异常, 因此异常的抛出是系统隐式的自动抛出, 不需要使用raise关键字 

Oracle中预定义下面一个预定义异常: (左往右分别是 异常名和异常代码)


-- author: csdn libertine1993
create or replace procedure pro_preddefine_exp 
as 
  para1 number := 1;
  para2 number := 0;
  para3 number;
  
  error_code number;
  error_msg varchar(64);
begin
  para3 := para1 / para2; --系统将会隐式的抛出 除数为0的异常
exception
  when zero_divide then
  insert into my_error_info(f_id, f_error_msg)
  values(sys_guid(), '这是使用预定义的异常名 zero_divide 捕获到的异常');
END PRO_PREDDEFINE_EXP;

结果:




2) 不给于异常名称, 只以others 关键字来对所有异常做一个笼统的处理.

实例:  尝试插入一条没有主键的记录, 捕获异常后, 只使用others做一个笼统的处理, 这里的处理是将异常信息插入我们自己建的my_error_info表. 

-- author: libertine1933 from csdn
-- 尝试将一条缺少主键的记录插入 mytest表, 获取抛出的异常并将异常信息插入 my_error_info表

create or replace procedure pro_testexception 
AS 
    errorcode number;            --异常代码
    errormesg varchar2(64);      --异常信息
begin
    --为了便于观察, 每次都会清空错误信息表内之前的记录
    delete from my_error_info;

    insert into mytest(f_price) values('123'); --mytest表
exception 
    when others then             --使用others而不是异常名, 因此我们只能对异常做一个笼统的操作
        errorcode := sqlcode;    --使用sqlcode 和 sqlerrm 必须先赋值给两个局部变量
        errormesg := substr(sqlerrm, 1, 64);
        insert into my_error_info(
            f_id,               --自己建的错误信息表中每条记录的ID, 由sys_guid()生成
            f_create_date,      --记录创建日期, 由sysdate生成
            f_error_code,       --错误代码
            f_error_msg         --错误信息
        )
        values(
            sys_guid(),  
            sysdate,
            errorcode,
            errormesg
        );
END PRO_TESTEXCEPTION;


由于 mytest表 的主键 F_CMID 不能为空, 所以插入失败,  系统自行抛出一个异常(这种常见的异常属于内部定义异常, 由系统自动抛出), 由于使用的是others, 我们并不能得知异常的具体归属, 所以只能做一个笼统的处理, 这里的笼统处理就是将异常信息记录在表中, 这样我们就能够看到下面这条记录 :




最后, 本文只是对Oracle异常处理做了一个大概的介绍, 关于Oracle中异常的传播, 重定义预定义异常等知识点, 有兴趣继续了解的请参阅Oracle 11g官方文档, 在此不做阐述.



你可能感兴趣的:(oracle,exception,error,plsql,handling,oracle异常处理)