果冻想
认真玩技术的地方

Oracle学习笔记——异常处理

说说异常

在总结PL/SQL的基础知识时,说到了以下内容:

[declare]
    -- declaration statements
    i integer;
begin
    -- executable statements

[exception]
    -- exception statements
end;

对于其中的exception没有进行详细的总结,那么exception在Oracle又是怎么样的呢?出现了exception又要如何处理呢?这篇文章就对Oracle中的exception进行详细的总结。

Oracle预定义异常

在Oracle中,异常分为以下两类:

  • Oracle预定义异常
  • 用户自定义异常

在Oracle中预定义的异常如下表所示:

异常名称 错误代码 产生原因
ACCESS_INTO_NULL 06530 为一个未初始化对象的属性赋值
CASE_NOT_FOUND 06592 在CASE过程中,WHEN后没有包含必要的条件分支并且没有ELSE子句
COLLECTION_IS_NULL 06531 使用未初始化的集合元素
CURSOR_ALREADY_OPEN 06511 游标已经打开
DUP_VAL_ON_INDEX 00001 在具有唯一索引的列上插入一个重复值
INVALID_CURSOR 01001 在无效的游标上进行操作
INVALID_NUMBER 01722 在一个SQL语句中,由于字符串并不代表一个有效的数字,导致字符串向数字转换时会发生错误。(在过程化语句中,会抛出异常VALUE_ERROR。)当FETCH语句的LIMIT子句表达式后面不是一个正数时,这个异常也会被抛出。
LOGIN_DENIED 01017 使用错误的用户名或密码登陆数据库
NO_DATA_FOUND 01403 SELECT INTO未返回行,或者程序引用了嵌套表中一个已经删除的元素,或者引用表中一个为初始化的元素
NOT_LOGGED_ON 01012 没有连接到数据库
PROGRAM_ERROR 06501 PL/SQL内部错误
ROWTYPE_MISMATCH 06504 赋值语句中使用的主游标变量和PL/SQL游标变量的类型不兼容
SELF_IS_NULL 30625 调用一个未被实例化的对象的成员方法,内置的SELF参数总是指向这个对象,SELF会作为函数的第一个参数传递到这个成员方法,就好比C++中的this
STORAGE_ERROR 06500 内存溢出或者内存不足
SUBSCRIPT_BEYOND_COUNT 06533 程序引用一个嵌套表或变长数组元素,但使用的下标索引超过嵌套表或变长数组元素总个数
SUBSCRIPT_OUTSIDE_LIMIT 06532 程序引用一个嵌套表或变长数组,但使用的下标索引不在合法的范围内
SYS_INVALID_ROWID 01410 从字符串向ROWID转换发生错误,因为字符串并不代表一个有效的ROWID
TIMEOUT_ON_RESOURCE 00051 当Oracle请求资源时,发生超时现象
TOO_MANY_ROWS 01422 SELECT INTO返回的行数太多
VALUE_ERROR 06502 发生算术、转换、截位或长度约束错误。例如,当我们的程序把一个字段的值放到一个字符变量中时,如果值的长度大于变量的长度,PL/SQL就会终止赋值操作并抛出异常VALUE_ERROR。在过程化语句中,如果字符串向数字转换失败,异常VALUE_ERROR就会被抛出(在SQL语句中,异常INVALID_NUMBER会被抛出)
ZERO_DIVIDE 01476 程序尝试除以0

用户自定义异常

和其它语言一样,我们也可以定义我们满足我们自己要求的异常,自定义一样的语法格式如下:

PRAGMA EXCEPTION_INIT(exception_name, -Oracle_error_number);
  • exception_name:异常的名字
  • Oracle_error_number:错误编号,以符号'-'开始,范围从-20000~-20999

触发异常

定义了那么多异常,那么在程序中如何抛出异常呢?在Oracle中有以下三种方式触发异常:

  • 由Oracle自动触发异常
  • 使用RAISE语句手工触发
  • 调用存储过程RAISE_APPLICATION_ERROR手工触发

下面的代码将演示Oracle自动触发异常:

-- Created on 2015-7-14 by JellyThink 
declare 
    iA NUMBER(2) := 10;
begin
    iA := iA / 0; -- Oracle自动触发异常
    dbms_output.put_line(iA);
exception
    when ZERO_DIVIDE then
        dbms_output.put_line('Error Code:' || SQLCODE || ' ' || SQLERRM);
    when others then
        dbms_output.put_line('Others Exception');
end;

下面的代码将演示使用RAISE语句手工触发异常:

-- Created on 2015-7-14 by JellyThink 
declare 
    myException EXCEPTION;
begin
    RAISE myException; -- RAISE手工触发异常
exception
    when others then
        dbms_output.put_line('Others Exception');
end;

下面的代码将演示使用RAISE_APPLICATION_ERROR触发异常:

-- Created on 2015-7-14 by JellyThink 
declare 
    myException EXCEPTION;
    PRAGMA EXCEPTION(myException, -20009);
begin
    RAISE_APPLICATION_ERROR(-20009, 'Exception'); -- 这里可以指定异常信息
exception
    when myException then
        dbms_output.put_line('myException Exception');
end;

异常传递

先来看看下面这段代码:

-- Created on 2015-7-15 by JellyThink 
declare 
    i Number;
begin
    i := 10;
    declare
    begin
        i := i / 0; -- 嵌套块中抛出异常
    /*exception
        when ZERO_DIVIDE then
            dbms_output.put_line('Error');*/ -- 嵌套块不处理这个异常
    end;
exception
    -- 在这里处理子块抛出的异常
    when ZERO_DIVIDE then
        dbms_output.put_line('Error Code:' || SQLCODE || ' ' || SQLERRM);
    when others then
        dbms_output.put_line('Error Code:' || SQLCODE || '  ' || SQLERRM);
end;

在一个块中,只能有一个异常处理部分,在不同的块中,可以定义多个异常处理部分。父块中可以定义异常处理,子块中也可以定义自己的异常处理。当一个子块的异常发生时,如果在子块的异常处理部分没有进行处理,该异常会传递到父块中,如果父块中没有对应的异常处理部分,那么这个异常会继续向上传递。

总结

异常的处理在一个程序中是必不可少的,也是你的代码走向完美的一个必要的部分。只有熟悉的掌握了异常处理,才能更好的服务于你的代码。想想我们现在系统中的存储过程,都没有异常处理,哦,谁写的,我保证不打死你。

果冻想,认真玩技术的地方。

2015年7与15日 于呼和浩特。

未经允许不得转载:果冻想 » Oracle学习笔记——异常处理
网站维护离不开您的支持,您可以赞助本站,谢谢支持
×

感谢您的支持,我们会一直保持!

扫码支持
请土豪扫码随意打赏

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

赞助本站
关注微信公众号
关注微信公众号和果冻一起分享你的疑惑与心得。
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

玩技术,我们是认真的

联系我们关于果冻