题目 部分

Oracle中的异常可以分为哪几类?

 

     答案部分

 

 

   异常(EXCEPTION)处理是用来处理正常执行过程中未预料到的事件,包括程序块的异常处理、预定义的错误和自定义错误。如果PL/SQL程序块一旦产生异常,而程序并没有指出如何处理,那么程序就会自动终止运行。

   

异常处理部分一般放在PL/SQL程序体的后半部分,结构如下所示:

EXCEPTION

   WHEN first_exception  THEN  <code to handle first exception >

   WHEN second_exception  THEN  <code to handle second exception >

   WHEN OTHERS THEN <code to handle OTHERS exception >

对于异常处理,需要注意以下几点内容:

(1)异常处理可以按任意次序排列,但OTHERS必须放在最后。

(2)当程序出现异常时,程序立即暂停工作,跳转到EXCEPTION部分。使用WHEN … THEN来处理系统定义的异常。使用WHEN OTHERS THEN处理未定义的异常。

(3)当异常处理结束后,Oracle就将处理权交给调用者。结束PL/SQL块的运行。

Oracle将异常分为预定义异常、非预定义异常和自定义异常三种。

1、预定义异常Predefined

当PL/SQL应用程序违反了Oracle规定的限制时,就会隐含地触发一个内部异常,这就是预定义异常。预定义异常用于处理常见的Oracle错误,对这种异常情况的处理,无需在程序中定义,由Oracle自动将其触发。它们全部放在PL/SQL自带的标准包中,这样程序员就无需再次定义了。预定义异常大约有20多个,下表是一些常见的预定义异常:

表 5-3 Oracle预定义异常

错误号

异常错误信息名称

说明

ORA-01403

NO_DATA_FOUND

SELECT INTO没有找到数据

ORA-01422

TOO_MANY_ROWS

SELECT INTO返回多行

ORA-06501

PROGRAM_ERROR

内部错误,需重新安装数据字典视图和PL/SQL包

ORA-06511

CURSOR_ALREADY_OPEN

试图打开一个已存在的游标

ORA-06530

ACCESS_INTO_NULL

试图为NULL对象的属性赋值

ORA-01012

NOT_LOGGED_ON

没有连接到Oracle

ORA-01001

INVALID_CURSOR

试图使用一个无效的游标

ORA-00061

TRANSACTION_BACKED_OUT

由于发生死锁事务被撤消

ORA-00051

TIMEOUT_ON_RESOURCE

在等待资源时发生超时

ORA-00001

DUP_VAL_ON_INDEX

试图破坏一个唯一性限制

ORA-01017

LOGIN_DENIED

无效的用户名/口令

ORA-01476

ZERO_DIVIDE

试图被零除

ORA-01722

INVALID_NUMBER

转换一个数字失败

ORA-06500

STORAGE_ERROR

内存不够或内存被破坏触发的内部错误

ORA-06502

VALUE_ERROR

赋值操作,变量长度不足,触发该异常

ORA-06504

ROWTYPE_MISMATCH

宿主游标变量与PL/SQL变量有不兼容行类型

ORA-06531

COLLECTION_IS_NULL

试图给没有初始化的嵌套表变量或者VARRY变量赋值

ORA-06532

SUBSCRIPT_OUTSIDE_LIMIT

对嵌套或VARRAY索引使用了负数

ORA-06533

SUBSCRIPT_BEYOND_COUNT

对嵌套或VARRAY索引的引用大于集合中元素的个数

预定义异常的示例如下所示:

SYS@lhrdb> SET SERVEROUTPUT ON

SYS@lhrdb> DECLARE

  2    V_ENAME SCOTT.EMP.ENAME%TYPE;

  3    V_SAL   SCOTT.EMP.SAL%TYPE;

  4    V_INPUT SCOTT.EMP.SAL%TYPE := 100;

  5  BEGIN

  6    SELECT ENAME, SAL INTO V_ENAME, V_SAL FROM SCOTT.EMP WHERE SAL = V_INPUT;

  7    DBMS_OUTPUT.PUT_LINE(V_ENAME || ',' || V_SAL);

  8  EXCEPTION

  9    WHEN NO_DATA_FOUND THEN

 10      DBMS_OUTPUT.PUT_LINE('没找到任何数据');

 11    WHEN TOO_MANY_ROWS THEN

 12      DBMS_OUTPUT.PUT_LINE('找到多行数据,建议使用游标');

 13    WHEN OTHERS THEN

 14      DBMS_OUTPUT.PUT_LINE('出错了!!');

 15      DBMS_OUTPUT.PUT_LINE(SQLCODE || ',' || SQLERRM);

 16    

 17  END;

 18  /

没找到任何数据

PL/SQL procedure successfully completed.

2、非预定义异常Non Predefined

非预定义异常用于处理预定义异常不能处理的异常,即其它标准的Oracle错误。使用预定义异常只能处理系统预定义的20多个Oracle错误,而当使用PL/SQL开发应用程序时,可能会遇到其它的一些Oracle错误。例如,在PL/SQL块中执行DML语句时,违反了约束规定等等。在这样的情况下,就可以使用非预定义异常来处理。

Oracle提供了2个函数SQLCODE和SQLERRM用于返回错误信息:

l SQLCODE:返回错误代码

l SQLERRM:返回与错误代码关联的消息

这样就可以在错误日志表中记录程序在执行过程中发生的错误信息了。

非预定义异常的示例如下所示:

SYS@lhrdb> SET SERVEROUTPUT ON

SYS@lhrdb> DECLARE

  2    FK_EXCEPTION EXCEPTION; --定义一个异常类型的变量

  3    PRAGMA EXCEPTION_INIT(FK_EXCEPTION, -2292); --将该变量和指定的错误码绑定

  4    V_ERROR_CODE    NUMBER;

  5    V_ERROR_MESSAGE VARCHAR2(255);

  6  BEGIN

  7    DELETE FROM SCOTT.DEPT WHERE DEPTNO = 20;

  8  EXCEPTION

  9    WHEN FK_EXCEPTION THEN

 10      --可以用异常类型的名字进行异常的捕获

 11      DBMS_OUTPUT.PUT_LINE('找到子记录,删除失败');

 12    WHEN OTHERS THEN

 13      ROLLBACK;

 14      DBMS_OUTPUT.PUT_LINE(SQLCODE || ',' || SQLERRM);

 15  END;

 16  /

找到子记录,删除失败

PL/SQL procedure successfully completed.

3、自定义异常User_define

自定义异常用于处理与Oracle错误无关的其它情况。对这种异常情况的处理,需要用户在程序中定义,然后显式地在程序中将其触发。

预定义异常和自定义异常都是与Oracle错误相关的,并且出现的Oracle错误会隐含地触发相应的异常;而自定义异常与Oracle错误没有任何关联,它是由开发人员为特定情况所定义的异常。当与一个异常相关的错误出现时,就会隐含触发该异常。用户定义异常是通过显式使用RAISE语句来触发。当触发一个异常时,控制程序就转到异常块部分,执行错误处理代码。

自定义异常的示例如下所示:

SYS@lhrdb> SET SERVEROUTPUT ON

SYS@lhrdb> DECLARE

  2    V_SAL   SCOTT.EMP.SAL%TYPE;

  3    V_ENAME SCOTT.EMP.ENAME%TYPE;

  4    V_EMPNO SCOTT.EMP.EMPNO%TYPE := 6;

  5    SALARY_EXCEPTION EXCEPTION; --定义异常的类型(名字)

  6  BEGIN

  7    SELECT ENAME, SAL INTO V_ENAME, V_SAL FROM SCOTT.EMP WHERE EMPNO = V_EMPNO;

  8    IF V_SAL < 1500 THEN

  9      V_SAL := V_SAL + 100;

 10      DBMS_OUTPUT.PUT_LINE(V_ENAME || '涨工资后:' || V_SAL);

 11    ELSE

 12      RAISE SALARY_EXCEPTION; --抛出自定义的异常

 13    END IF;

 14  EXCEPTION

 15    WHEN SALARY_EXCEPTION THEN

 16      --捕获自定义的异常

 17      DBMS_OUTPUT.PUT_LINE('薪金没有达到最低水平,不需要涨工资');

 18    WHEN NO_DATA_FOUND THEN

 19      DBMS_OUTPUT.PUT_LINE('没有找到' || V_EMPNO || '编码的员工');

 20    WHEN OTHERS THEN

 21      DBMS_OUTPUT.PUT_LINE(SQLCODE || ',' || SQLERRM);

 22  END;

 23  /

没有找到6编码的员工

 

PL/SQL procedure successfully completed.

 

【DB笔试面试445】Oracle中的异常可以分为哪几类?_sql