09-Oracle异常处理

本章内容

异常概述
异常处理过程
异常的传播

异常概述

        Oracle错误处理机制

        异常的类型

Oracle错误处理机制

        1、Oracle中对运行时错误的处理采用了异常处理机制。

        2、一个错误对应一个异常,当错误产生时抛出相应的异常,并被异常处理器捕获,程序控制权传递给异常处理器,由异常处理器来处理运行时错误。

异常的类型

预定义的 Oracle 异常( Oracle 错误)
非预定义的 Oracle 异常( Oracle 错误)
用户定义的异常(用户定义错误)

预定义的Oracle异常

  Oracle 错误产生时,与错误对应的预定义异常被自动抛出,通过捕获该异常可以对错误进行处理。
  常用预定义异常包括:

异常情况名

错误代码

描述

CURSOR_ALREADY_OPEN

ORA-06511

尝试打开已经打开的游标

INVALID_CURSOR

ORA-01001

不合法的游标操作(如要打开已经关闭的游标)

NO_DATA_FOUND

ORA-01403

没有发现数据

TOO_MANY_ROWS

ORA-01422

一个SELECT  INTO语句匹配多个数据行

INVALID_NUMBER

ORA-01722

转换成数字失败 X

VALUE_ERROR

ORA-06502

截断、算法或转换错误,通常出现在赋值错误

ZERO_DIVIDE

ORA-01476

除数为0

ROWTYPE_MISMATCH

ORA-06504

主机游标变量与PL/SQL游标变量类型不匹配

异常情况名

错误代码

描述

DUP_VAL_ON_INDEX

ORA-00001

违反唯一性约束或主键约束

SYS_INVALID_ROWID

ORA-01410

转换成ROWID失败

TIMEOUT_ON_RESOURCE

ORA-00051

在等待资源中出现超时

LOGIN_DENIED

ORA-01017

无效用户名/密码

CASE_NOT_FOUND

ORA-06592

没有匹配的WHEN子句

NOT_LOGGED_ON

ORA-01012

没有与数据库建立连接

STORAGE_ERROR

ORA-06500

PL/SQL内部错误

PROGRAM_ERROR

ORA-06501

PL/SQL内部错误

异常情况名

错误代码

描述

ACCESS_INTO_NULL

ORA-06530

给空对象属性赋值

COLLECTION_IS_NULL

ORA-06531

对某NULL PL/SQL表或可变数组试图应用集合方法,而不是EXISTS

SELF_IS_NULL

ORA-30625

调用空对象实例的方法

SUBSCRIPT_BEYOND_COUNT

ORA-06533

对嵌套表或数组索引引用时超出集合中元素的数量

SUBSCRIPT_OUTSIDE_LIMIT

ORA-06532

对嵌套表或可变数组索引的引用超出声明的范围

非预定义异常

  有一些 Oracle 错误没有预定义异常与其关联,需要在语句块的声明部分声明一个异常名称,然后通过编译指示 PRAGMA EXCEPTION_INIT 将该异常名称与一个 Oracle 错误相关联。此后,当执行过程出现该错误时将自动抛出该异常。

声明一个异常名称
  e_integrity EXCEPTION;
将异常与一个 Oracle 错误号相绑定
  PRAGMA EXCEPTION-INIT(e_integrity.-2291)
示例
  DECLARE
    e_deptno_fk EXCEPTION;
    PRAGMA EXCEPTION_INIT(e_deptno_fk,-2292);
  BEGIN
  ……
  EXCEPTION
  ……
  END;

用户自定义的异常

  用户定义错误是指,有些操作并不会产生 Oracle 错误,但是从业务规则角度考虑,认为是一种错误。
  用户自定义异常必须在声明部分进行声明。
  当异常发生时,系统不能自动触发,需要用户使用 RAISE 语句。
  在异常处理部分捕捉并处理异常。

异常处理过程

异常的定义
异常的抛出
异常的捕获与处理
OTHERS 异常处理器

异常处理分3个步骤进行:
  在声明部分为错误定义异常,包括非预定义异常和用户定义异常。
  在执行过程中当错误产生时抛出与错误对应的异常。
  在异常处理部分通过异常处理器捕获异常,并进行异常处理。

异常的定义

Oracle 中的 3 种异常,其中预定义异常由系统定义,而其他两种异常则需要用户定义。
定义异常方法
  e_exception EXCEPTION;
如果是非预定义的异常,需要将异常与一个 Oracle 错误相关联,其语法为:
  PRAGMA EXCEPTION_INIT(e_exception, -#####);
注意
  Oracle 内部错误号用一个负的 5 位数表示,如 -02292 。其中

   -20999-20000为用户定义错误的保留号。

异常的抛出

由于系统可以自动识别 Oracle 内部错误,因此当错误产生时系统会自动抛出与之对应的预定义异常或非预定义异常。但是,系统无法识别用户定义错误,因此当用户定义错误产生时,需要用户手动抛出与之对应的异常。
用户定义异常的抛出语法为
  RAISE user_define_exception

异常的捕获与处理

异常处理器的基本形式为
  EXCEPTION
  WHEN exception1[OR excetpion2 ]THEN
     sequence_of_statements1;
  WHEN exception3[OR exception4 ]THEN
     sequence_of_statements2;
  ……
  WHEN OTHERS THEN
     sequence_of_statementsn;
  END;
注意
  一个异常处理器可以捕获多个异常,只需在 WHEN 子句中用

    OR连接即可;

  一个异常只能被一个异常处理器捕获,并进行处理。
查询名为SMITH的员工工资,如果该员工不存在,则输出“There is not such an employee!” ;如果存在多个同名的员工,则输出其员工号和工资

DECLARE
  v_sal emp.sal%type;
BEGIN
  SELECT sal INTO v_sal FROM emp WHERE ename='SMITH';
  DBMS_OUTPUT.PUT_LINE(v_sal);
EXCEPTION
  WHEN NO_DATA_FOUND THEN 
    DBMS_OUTPUT.PUT_LINE('There is not such an emplyee!');
  WHEN TOO_MANY_ROWS THEN
    FOR v_emp IN (SELECT * FROM emp WHERE ename='SMITH')    
    LOOP
       DBMS_OUTPUT.PUT_LINE(v_emp.empno||' '||v_emp.sal);
    END LOOP;
END;
删除dept表中部门号为10的部门信息,如果不能删除则输出“There are subrecords in emp table!”
DECLARE
  e_deptno_fk EXCEPTION;
  PRAGMA EXCEPTION_INIT(e_deptno_fk,-2292);
BEGIN
  DELETE FROM dept WHERE deptno=10;
EXCEPTION
  WHEN e_deptno_fk THEN
     DBMS_OUTPUT.PUT_LINE(' There are subrecords in emp 
                                                table!');
END;
修改7844员工的工资,保证修改后工资不超过6000
DECLARE
  e_highlimit EXCEPTION;
  v_sal emp.sal%TYPE;
BEGIN
  UPDATE emp SET sal=sal+100 WHERE empno=7844 RETURNING sal INTO v_sal;
  IF v_sal>6000 THEN 
     RAISE e_highlimit;
  END IF;
EXCEPTION
  WHEN e_highlimit THEN
    DBMS_OUTPUT.PUT_LINE('The salary is too large!');
    ROLLBACK;
END; 

OTHERS异常处理器

OTHERS 异常处理器是一个特殊的异常处理器,可以捕获所有的异常。
通常, OTHERS 异常处理器总是作为异常处理部分的最后一个异常处理器,负责处理那些没有被其他异常处理器捕获的异常。

DECLARE
  v_sal emp.sal%TYPE;
  e_highlimit EXCEPTION;
BEGIN
  SELECT sal INTO v_sal FROM emp WHERE ename='JOAN';
  UPDATE emp SET sal=sal+100 WHERE empno=7900;
  IF v_sal>6000 THEN 
    RAISE e_highlimit;
  END IF;
EXCEPTION
  WHEN e_highlimit THEN
    DBMS_OUTPUT.PUT_LINE('The salary is too large!');
   ROLLBACK;
  WHEN OTHERS THEN
   DBMS_OUTPUT.PUT_LINE('There is some wrong in 
                                                 selecting!');
END; 
可以通过两个函数来获取错误相关信息。
 
SQLCODE :返回当前错误代码。
如果是用户定义错误返回值为 1
如果是 ORA-1403 NO DATA FOUND 错误,返回值为 100
其他 Oracle 内部错误返回相应的错误号。
  SQLERRM :返回当前错误的消息文本。
如果是 Oracle 内部错误,返回系统内部的错误描述;
如果是用户定义错误,则返回信息文本为“ User-defined Exception”
DECLARE
  v_sal emp.sal%TYPE;
  e_highlimit EXCEPTION;
  v_code NUMBER(6);
  v_text VARCHAR2(200);
BEGIN
  SELECT sal INTO v_sal FROM emp WHERE ename='JOAN';
  UPDATE emp SET sal=sal+100 WHERE empno=7900;
  IF v_sal>6000 THEN 
    RAISE e_highlimit;
  END IF;
EXCEPTION
  WHEN e_highlimit THEN
    DBMS_OUTPUT.PUT_LINE('The salary is too large!');
    ROLLBACK;
  WHEN OTHERS THEN
    v_code:=SQLCODE;
    v_text:=SQLERRM;   
    DBMS_OUTPUT.PUT_LINE(v_code||' '||v_text);
END; 

异常的传播

执行部分的异常
声明部分和异常处理部分的异常

执行部分异常的传播

如果当前语句块有该异常的处理器,则执行之,并且成功完成该语句块。然后,控制权传递到外层语句块。
如果当前语句块没有该异常的处理器,则通过在外层语句块中产生该异常来传播该异常。然后,执行对外层语句块执行步骤 1 。如果没有外层语句块,则该异常将传播到调用环境。

DECLARE
  v_sal emp.sal%TYPE;
BEGIN
  BEGIN  
    SELECT sal INTO v_sal FROM emp WHERE ename='JOAN';
  EXCEPTION
    WHEN NO_DATA_FOUND THEN 
      DBMS_OUTPUT.PUT_LINE('There is not such an employee!');
  END;
  DBMS_OUTPUT.PUT_LINE('Now this is outputted by outer 
                                          block!');
END;
/
There is not such an employee!
Now this is outputted by outer block! 
DECLARE
  v_sal emp.sal%TYPE;
BEGIN
  BEGIN  
    SELECT sal INTO v_sal FROM emp WHERE deptno=10;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN 
      DBMS_OUTPUT.PUT_LINE('There is not such an employee!');
  END;
  DBMS_OUTPUT.PUT_LINE('Now this is outputted by outer 
                                           block!');
EXCEPTION
  WHEN TOO_MANY_ROWS THEN
    DBMS_OUTPUT.PUT_LINE('There are more than one employee!');
END;
/
There are more than one employee!

声明部分和异常处理部分的异常

        声明部分和异常处理部分的异常会立刻传播到外层语句块的异常处理部分,即使当前语句块有该异常的异常处理器。

BEGIN
  DECLARE
v_number NUMBER(6) :='ABC';
BEGIN
    v_number:=10;
  EXCEPTION
    WHEN OTHERS THEN
       DBMS_OUTPUT.PUT_LINE('This is outputted by inner         
                                                 block!');
  END;
EXCEPTION
WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('This is outputted by outer 
                                              block!');
END;
/
This is outputted by outer block! 

结论

          无论是执行部分的异常,还是声明部分或异常处理部分的异常,如果在本块中没有处理,最终都将向外层块中传播。
          通常在程序最外层块的异常处理部分放置OTHERS 异常处理器,以保证没有错误被漏掉检测,否则错误将传递到调用环境。

        本人从事软件项目开发20多年,2005年开始从事Java工程师系列课程的教学工作,录制50多门精品视频课程,包含java基础,jspweb开发,SSH,SSM,SpringBoot,SpringCloud,人工智能,在线支付等众多商业项目,每门课程都包含有项目实战,上课PPT,及完整的源代码下载,有兴趣的朋友可以看看我的在线课堂

讲师课堂链接:https://edu.csdn.net/lecturer/893

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Oracle异常处理是指在Oracle数据库中对异常情况进行捕获和处理的机制。当在数据库操作过程中发生错误或异常时,可以使用异常处理来进行错误处理和恢复操作,以保证数据库的稳定性和数据的完整性。 在Oracle中,异常处理主要通过以下几个关键字来实现: 1. BEGIN和END:用于定义一个异常处理块,将需要进行异常处理的代码放在BEGIN和END之间。 2. EXCEPTION:用于定义异常处理块中的异常处理部分,可以在EXCEPTION块中捕获和处理异常。 3. DECLARE:用于声明异常变量,可以在DECLARE块中定义异常变量,用于捕获和处理异常。 4. RAISE:用于手动抛出异常,可以使用RAISE语句在代码中主动抛出异常。 5. WHEN:用于指定异常类型,可以使用WHEN语句来指定需要捕获和处理的异常类型。 下面是一个简单的Oracle异常处理的示例: ``` BEGIN DECLARE v_num1 NUMBER := 10; v_num2 NUMBER := 0; v_result NUMBER; BEGIN -- 捕获除零异常 IF v_num2 = 0 THEN RAISE ZERO_DIVIDE; END IF; -- 计算结果 v_result := v_num1 / v_num2; -- 输出结果 DBMS_OUTPUT.PUT_LINE('Result: ' || v_result); EXCEPTION -- 处理除零异常 WHEN ZERO_DIVIDE THEN DBMS_OUTPUT.PUT_LINE('Error: Division by zero'); -- 处理其他异常 WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM); END; END; ``` 在上述示例中,首先声明了两个变量v_num1和v_num2,并将v_num2的值设置为0,然后进行除法运算。由于除数为0,会抛出ZERO_DIVIDE异常,然后在EXCEPTION块中捕获并处理该异常,输出错误信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CSDN专家-赖老师(软件之家)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值