Oracle异常处理

即使是写得最好的PL/SQL程序也会遇到错误或未预料到的事件。一个优秀的程序都应该能够正确处理各种出错情况,并尽可能从错误中恢复。任何ORACLE错误(报告为ORA-xxxxx形式的Oracle错误号)、PL/SQL运行错误或用户定义条件(不一写是错误)都可以。当然了,PL/SQL编译错误不能通过PL/SQL异常处理来处理,因为这些错误发生在PL/SQL程序执行之前。

ORACLE 提供异常情况(EXCEPTION)和异常处理(EXCEPTION HANDLER)来实现错误处理。

1 .异常的概念

在设计或运行一个程序时,常出现这样或那样的错误。针对这类错误,采取相应的措施。这就是异常处理(EXCEPTION)

异常处理就是针对系统中发生的各种错误所采取的处理措施,也叫例外.

1、异常的定义格式:

BEGIN
…;
EXCEPTION
  WHEN 异常情况 1[ OR 异常情况 2 …] THEN
     …;
  WHEN 异常情况 3[ OR 异常情况 4 …] THEN
    …;
  WHEN OTHERS THEN
…;
END

说明:

  • 在块中开始一个出错处理部分必须以关键子EXCEPTION开始;
  • 将WHEN OTHERS 子句放置在所有其他出错处理子句的后面。最多只能有一个WHEN OTHERS 子句;
  • 可以在块中定义多个句柄(HANDLER),每个句柄包含一组语句;
  • 当一个错误发生时,在离开块之前,PL/SQL只处理一个句柄

2、异常的类型

oracle预定义的异常
oracle预定义的异常,当这些异常情况发生时,系统可捕获异常并在程序中根据异常名称对程序进行异常处理。
Oracle非预定义的异常
是其他标准的Oracle错误。对这种异常情况的处理,需要用户在PL/SQL块的declare部分中定义,并在异常触发后对其处理。
用户自定义的异常
是由程序员根据逻辑规则定义的一些异常并对它进行处理。
注意:ORACLE预定义异常和非预定义异常都是由ORACLE进行判断错误

2.Oracle预定义的异常处理

ORACLE错误

对应的错误名

描述

ORA_00001

DUP_VAL_ON_INDEX

试图通过一个重复值更新或插入一条语句,即违反了唯一性约束

ORA_00051

TIMEOUT_ON_RESOURCE

在等待资源时发生超时现象,例如DDL操作加的排他表级锁

ORA_01001

INVALID_CURSOR

非法的游标操作,例如游标在没有打开时执行FETCH操作

ORA_01522

INVALID_NUMBER

字符串向数字转换失败,即有个无效字符

ORA_01012

NO_LOGGED_ON

在没有连接到ORACLE之前,对数据库进行调用

ORA_01015

LOGIN_DENIED

在连接中提供了无效的用户名/口令

ORA_01403

NO_DATA_FOUND

执行SELECT语句未查询到数据

ORA_01410

SYS_INVALID_ROWID

一个隐式的CHARTOROWID转换时,包含了无效的字符或格式

ORA_01422

TOO_MANY_ROWS

未使用游标,SELECT语句返回了多行数据

ORA_06502

VALUE_ERROR

由于长度类型不合适,出现数字、数据转换、字符串或限制型错误

ORA_01456

ZERO_DIVIDE

被零除

ORA_06500

STORAGE_ERROR

如果PL/SQL运行时内存被破坏或不够就会引发内部的PL/SQL错误

ORA_06501

PROGRAM_ERROR

内部的PL/SQL错误

ORA_06504

ROWTYPE_MISMATCH

游标变量和PL/SQL结果集之间数据类型不匹配

ORA_06511

CURSOR_ALREADY_OPEN

试图打开一个已经打开的游标

ORA_06530

ACCESS_INTO_NULL

参考了没有初始化的数据库对象、LOB或其他非集合的符合类型(即这些对象的值都是NULL)

ORA_06531

COLLECTION_IS_NULL

参考了没有初始化的嵌套表或VARRAY集合中的元素、或调用了没有初始化的集合方法

ORA_06532

SUBSCRIPT_OUTSIDE_LIMIT

使用了一个下标比VARRAY边界值高的云素

ORA_06533

SUBSCRIPT_BEYOND_COUNT

使用了一个比嵌套表或VARRAY初始化元素个数多的元素

 注:红色是比较常用到的

对这种异常情况的处理,只需在PL/SQL块的异常处理部分,直接引用相应的异常情况名,并对其完成相应的异常错误处理即可。

例1:对异常DUP_VAL_ON_INDEX的捕获及处理.向产品表中插入一条记录,当主键值重复时,输出该记录的主键值已经存在.

BEGIN
     INSERT INTO products(productid,productname)
     values(&prodid,’&prodname’);
  EXCEPTION
    WHEN DUP_VAL_ON_INDEX THEN
      dbms_output.put_line('该主键值已存在');
    WHEN OTHERS THEN
      dbms_output.put_line(‘其他错误');
 END;

例2:对异常NO_DATA_FOUND和TOO_MANY_ROWS的捕获及处理.
查询某类别的产品信息,如不存在则显示异常’没有找到该产品’,如查到多行则显示异常‘查找到多个产品’,如只查到一行则显示产品编号、名称、单价

DECLARE
   rec_prod  products%rowtype;
BEGIN
   SELECT * INTO rec_prod  FROM products
   WHERE categoryid=&cateid;   
      dbms_output.put_line('产品编号'||rec_prod.productid);
      dbms_output.put_line('产品名称'||rec_prod.productname);
      dbms_output.put_line('产品单价'||rec_prod.unitprice);
 EXCEPTION
    WHEN NO_DATA_FOUND THEN
      dbms_output.put_line('没有找到该产品');
   WHEN TOO_MANY_ROWS THEN
      dbms_output.put_line('查找到多个产品');
 END;

3 . 非预定义的Oracle异常

 要使用非预定义的Oracle异常,则用户必须首先进行定义。步骤如下:
(1)在PL/SQL块的declare定义部分定义异常名:
<exception_name>  EXCEPTION;
(2)使用pragma exception_init语句,将其定义好的异常名与标准的Oracle错误编号联系起来:
pragma  exception_init(<exception_name >, <handle_code>);
(3)在PL/SQL块异常的处理部分对异常情况做出相应的处理。
例3:定义一个非预定义异常,对删除产品表中产品编号为1的产品的异常进行异常处理

DECLARE
    Fk_delete  EXCEPTION;
    PRAGMA EXCEPTION_INIT (Fk_delete ,-2292);
BEGIN
    DELETE products WHERE productid=1;              
 EXCEPTION
WHEN Fk_delete   THEN
       dbms_output.put_line(‘在另一个表中引用了该记录’);
WHEN others  THEN
       dbms_output.put_line(‘其它错误’||sqlcode);
      END;

例4:向产品表中插入一条记录,当主键重复时,输出’该主键值已存在’, 当产品名为空时,输出’违反了非空约束

 DECLARE
    Name_null EXCEPTION;
   PRAGMA exception_init(name_null, -1400);
BEGIN
     INSERT INTO products(productid,productname)
     values(&prodid,’&prodname’);
  EXCEPTION
    WHEN DUP_VAL_ON_INDEX THEN
      dbms_output.put_line('该主键值已存在');
    WHEN Name_null THEN
      dbms_output.put_line('违反了非空约束');
END;

4. 用户自定义的异常

当与一个异常错误相关的错误出现时,就会隐含触发该异常错误。用户定义的异常错误是通过显式使用 RAISE 语句来触发。当引发一个异常错误时,控制就转向到 EXCEPTION块异常错误部分,执行错误处理代码。

用户自定义异常的处理步骤

 例5:对产品表中单价小于等于3元的产品的打折状态更新为1.如果没有找到这样的产品则触发用户自定义异常,并提示”未找到相应产品”,否则显示更新了几条信息.

DECLARE
    prod_excep EXCEPTION;
BEGIN
   UPDATE products SET Discontinued=1WHERE unitprice<=3;
   IF sql%notfound THEN RAISE prod_excep;
   ELSE
     dbms_output.put_line(‘更新了’||sql%rowcount||’条记录’);
   END IF;
EXCEPTION
   WHEN prod_excep THEN
       dbms_output.put_line(‘未找到相应产品’);
END;  

 5.三种异常的简单比较

异常

描 述

处理方向

系统预定义的异常

在PL/SQL中经常出现的25个系统定义错误

不必定义,允许服务器隐式地触发它们

用户自定义的异常

开发者认为是非正确的一个条件

必须在说明部分定义,并且显示地触发它们

非预定义的系统异常

任何其他(25个以外的)服务器产生的标准错误

必须在说明部分定义,并且允许服务器隐式地触发它们

posted @ 2020-12-05 21:08  重雪  阅读(289)  评论(0编辑  收藏  举报