Oracle存储过程中异常处理总结

在Oracle中对于一些比较复杂的逻辑处理,我们通常会想到使用存储过程。但通常会遇到各种各样的异常,对于自己最近做过的一些项目中使用到存储过程中的异常处理做一个总结,希望对大家有所帮助。

有三种类型的异常错误:

    1. 预定义 ( Predefined )错误

  ORACLE预定义的异常情况大约有21个。对这种异常情况的处理,无需在程序中定义,由ORACLE自动将其引发。 

预定义异常
命名的系统异常产生原因
ACCESS_INTO_NULL未定义对象
CASE_NOT_FOUNDCASE 中若未包含相应的 WHEN ,并且没有设置 ELSE 时
COLLECTION_IS_NULL集合元素未初始化
CURSER_ALREADY_OPEN游标已经打开
DUP_VAL_ON_INDEX唯一索引对应的列上有重复的值
INVALID_CURSOR在不合法的游标上进行操作
INVALID_NUMBER内嵌的 SQL 语句不能将字符转换为数字
NO_DATA_FOUND使用 select into 未返回行,或应用索引表未初始化的元素时
TOO_MANY_ROWS执行 select into 时,结果集超过一行
ZERO_DIVIDE除数为0
SUBSCRIPT_BEYOND_COUNT元素下标超过嵌套表或 VARRAY 的最大值
SUBSCRIPT_OUTSIDE_LIMIT使用嵌套表或 VARRAY 时,将下标指定为负数
VALUE_ERROR赋值时,变量长度不足以容纳实际数据
LOGIN_DENIEDPL/SQL 应用程序连接到 oracle 数据库时,提供了不正确的用户名或密码
NOT_LOGGED_ONPL/SQL 应用程序在没有连接 oralce 数据库的情况下访问数据
PROGRAM_ERRORPL/SQL 内部问题,可能需要重装数据字典& pl./SQL 系统包
ROWTYPE_MISMATCH宿主游标变量与 PL/SQL 游标变量的返回类型不兼容
SELF_IS_NULL使用对象类型时,在 null 对象上调用对象方法
STORAGE_ERROR运行 PL/SQL 时,超出内存空间
SYS_INVALID_ID无效的 ROWID 字符串
TIMEOUT_ON_RESOURCEOracle 在等待资源时超时


    2. 非预定义 ( Predefined )错误

   即其他标准的ORACLE错误。对这种异常情况的处理,需要用户在程序中定义,然后由ORACLE自动将其引发。
    
      程序执行过程中,出现编程人员认为的非正常情况。对这种异常情况的处理,需要用户在程序中定义,然后显式地在程序中将其引发。
异常处理部分一般放在 PL/SQL 程序体的后半部,结构为:  

    3. 用户定义(User_define) 错误

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 >
END;


一、捕获系统预定义异常

    看下面的一个例子。

      有以下几种表,

     SYS_DEV ,系统设备表,  SYS_DMS   系统服务表。其中设备挂在在服务器上。现在要处理的问题是:删除或者修改服务器,为了保证数据库的一致性,我们必须更改挂在在服务器上的设备的。 SYS_DEV与 SYS_DMS是通过DMS_ID匹配。

     存储过程代如下:           

create or replace PROCEDURE DELETE_DMS (
   V_ROWNO          IN VARCHAR2,  ---输入要删除的DMS服务器的rowno字段。
   IS_SUCCESSED     OUT NUMBER, --操作成功标识,0表示失败,1表示成功。
   RETURN_MESSAGE   OUT VARCHAR2, ---返回用户提示。
   DEV_DATA   OUT SYS_REFCURSOR  ----输出要删除的DMS服务器上挂在的卡口信息。
)
as
/*********************************************************
功能说明:
        DMS服务器删除
参数说明:
       
*********************************************************/        
        DEV_NAME VARCHAR2(128);  
        DMS_CODED VARCHAR2(64);
        DMS_NAME VARCHAR2(128);
        vTEXT VARCHAR2(400);  
BEGIN  
      SELECT CODED INTO DMS_CODED FROM SYS_DMS WHERE SYS_DMS.ROWNO = V_ROWNO;
      SELECT TITLE INTO DMS_NAME FROM SYS_DMS WHERE SYS_DMS.CODED = DMS_CODED;
      vTEXT := 'SELECT SD1.ROWNO, SD1.TITLE AS DEV_NAME, SD1.CODED AS DEV_ID, 
                       SD1.DMSID,SD.TITLE AS DMS_NAME
                 FROM (SELECT TITLE ,CODED FROM SYS_DMS WHERE SYS_DMS.CODED =' 
                 ||DMS_CODED||')SD JOIN SYS_DEV SD1 ON (SD.CODED = SD1.DMSID)';
    IF DMS_CODED IS NOT NULL AND DMS_NAME IS NOT NULL THEN
      BEGIN
        SELECT  TITLE INTO DEV_NAME FROM SYS_DEV WHERE SYS_DEV.DMSID = DMS_CODED;   
          IF DEV_NAME IS  NOT NULL THEN 
          RETURN_MESSAGE := 'DMS服务器:'||DMS_NAME||',关联了其他卡口,
                            请先修改这些卡口关联的DMS服务器后执行删除操作。';
          OPEN DEV_DATA FOR vTEXT;
          IS_SUCCESSED := 0;         
          END IF;        
        EXCEPTION
          WHEN TOO_MANY_ROWS THEN
          RETURN_MESSAGE := 'DMS服务器:'||DMS_NAME||',关联了其他卡口,
                             请先修改这些卡口关联的DMS服务器后执行删除操作。';
          OPEN DEV_DATA FOR vTEXT;
          IS_SUCCESSED := 0;           
          WHEN NO_DATA_FOUND THEN
          DELETE FROM SYS_DMS WHERE ROWNO =   V_ROWNO;       
          RETURN_MESSAGE := '成功删除DMS服务器:'||DMS_NAME||'。'; 
          IS_SUCCESSED := 1;
        END;
    END IF;
      EXCEPTION 
        WHEN NO_DATA_FOUND THEN
          /*数据已删除,对同一个DMS服务器执行多次删除造成无法找到数据的异常。*/
          RETURN_MESSAGE := '此DMS服务器不存在或已经删除,请检查后重新输入。';
          IS_SUCCESSED := 0;
        WHEN TOO_MANY_ROWS THEN
        /*DMS_CODED 不能唯一标识DMS一行数据造成的异常。*/
          RETURN_MESSAGE := '数据库内部错误,请联系开发人员。';
          IS_SUCCESSED := 0;
END DELETE_DMS;

 总结:对于预定的异常只需在PL/SQL块的异常处理部分,直接引用相应的异常情况名,并对其完成相应的异常错误处理。

二、捕获非预定义异常

1. 在PL/SQL 块的定义部分定义异常情况:

<异常情况>  EXCEPTION;
PRAGMA EXCEPTION_INIT(<异常情况>, <错误代码>);

2. 将其定义好的异常情况,与标准的ORACLE错误联系起来,使用EXCEPTION_INIT语句:

3. 在PL/SQL 块的异常情况处理部分对异常情况做出相应的处理。

  例2:依然是上面的那个例子,删除服务器,确保服务器上没有挂载设备。

   存储过程代码如下:

CREATE OR REPLACE PROCEDURE DELETE_DMS (
   V_ROWNO          IN VARCHAR2,  ---输入要删除的DMS服务器的rowno字段。
   IS_SUCCESSED     OUT NUMBER, --操作成功标识,0表示失败,1表示成功。     
)
as
/*********************************************************
功能说明:
        DMS服务器删除
*********************************************************/        
        DMS_REMAINING EXCEPTION;        
BEGIN        
      DELETE FROM SYS_DMS WHERE ROWNO = V_ROWNO;
      IS_SUCCESSED :=1;
     EXCEPTION
       WHEN DMS_REMAINING THEN
         DBMS_OUTPUT.PUT_LINE('DMS服务器关联了其他设备,请先修改这些设备关联的DMS服务器后执行删除操作');
         IS_SUCCESSED :=0;
       WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
          IS_SUCCESSED :=0;
END DELETE_DMS;

三、捕获用户定义异常

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

对于这类异常情况的处理,步骤如下:

1. 在PL/SQL 块的定义部分定义异常情况:

<异常情况>  EXCEPTION;

2. RAISE <异常情况>

3. 在PL/SQL 块的异常情况处理部分对异常情况做出相应的处理。

例3:依然是上面那个例子,同样的处理。

代码如下:

create or replace PROCEDURE DELETE_DMS (
   V_ROWNO          IN VARCHAR2,  ---输入要删除的DMS服务器的rowno字段。
   IS_SUCCESSED     OUT NUMBER, --操作成功标识,0表示失败,1表示成功。
   RETURN_MESSAGE   OUT VARCHAR2, ---返回用户提示。  
)
as
/*********************************************************
功能说明:
        DMS服务器删除 
*********************************************************/        
        DMS_CODED VARCHAR2(64);        
	NO_RESULT EXCEPTION;
	TOO_MANY EXCEPTION;
BEGIN  
      SELECT CODED INTO DMS_CODED FROM SYS_DMS WHERE SYS_DMS.ROWNO = V_ROWNO;      
    IF  TOO_MANY_ROWS THEN
           RAISE  TOO_MANY;  
      END IF;  
    IF NO_DATA_FOUND AND SQL%NOTFOUND THEN
           RAISE NO_RESULT;
     END IF;
        EXCEPTION
          WHEN TOO_MANY THEN
          RETURN_MESSAGE := 'DMS服务器关联了其他卡口,请先修改这些卡口关联的DMS服务器后执行删除操作。';
          OPEN DEV_DATA FOR vTEXT;
          IS_SUCCESSED := 0;           
          WHEN NO_RESULT THEN
          DELETE FROM SYS_DMS WHERE ROWNO =  V_ROWNO;       
          RETURN_MESSAGE := '成功删除DMS服务器。'; 
          IS_SUCCESSED := 1;      
END DELETE_DMS;

          总结:对于异常的处理,应尽量调用预定义异常,因为捕获和处理都比较简单,当预定义异常无法满足时使用是采用非预定义异常和用户自定义的异常,

在异常处理过程中应该多细心,对于一些很少发生或者只在极端情况下发生的异常可以采取适当的捕获后抛掉。下一篇文章在专门讲解用户自定义异常的处理。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值