教学文章
Technology Exchange
热门课程
400电话

免费咨询热线
400-090-9964

教学文章

PLSQL异常处理

时间:2015-11-30 来源:

1、定义
异常:PL/SQL在执行的过程中所产生的标识符,PL/SQL中的一个警告或错误都被称为异常。
错误通常分为两类:
编译时错误--一般是语法错误,由PL/SQL引擎发现并报告给用户,程序本身不能处理,因为还没运行。
运行时错误--程序在运行时引发的错误,例如没返回结果与返回多个结果(只能返回一行结果的情况下)
异常处理---通常是指处理运行时错误。
     引发异常的一个重要原因是处理数据时发生错误。统计表明,SELECT语句、DML语句以及游标操作语句更容易引发异常。
     编写PL/SQL块的主要目的是处理数据,而PL/SQL块在逻辑上与数据是分开的,程序员根本无法预料数据的变化。
     例如,要查询部门10的员工,程序员根本不知道这个部门中有没有员工, 有一个还是有多个员工。
     所以在编写程序时,程序员应该考虑各种可能出现的异常,在程序中编写这些异常的处理代码,这样的程序才能经受各种错误的考验。
2、预定义异常
预定义异常:Oracle把一些常见的错误定义为有名字的异常,这就是预定义的异常。【有异常代码,异常名称,异常消息】
                   Oracle有许多预定义的异常,在进行处理时不需要再定义,只需要编写相应的异常处理程序即可。
                          当PL/SQL块执行发生错误时,数据库服务器将自动抛出相应的异常,并执行编写的异常处理程序。
 
预定义说明的 oracle 异常
 
ORACLE 错误       异常名                             说明
ORA-0001            Dup_val_on_index            试图破坏一个唯一性限制
ORA-0051            Timeout-on-resource        在等待资源时发生超时
ORA-0061            Transaction-backed-out     由于发生死锁事务被撤消.
ORA-1001            Invalid-cursor                  试图使用一个无效的游标
ORA-1012            Not-logged-on                 没有连接到ORACLE
ORA-1017            Login-denied                   无效的用户名/口令
ORA-1403            No_data_found                没有找到数据
ORA-1422            Too-many-rows               select into 返回多行
ORA-1476            Zero-divide                      试图被零除
ORA-1722            Invalid-number                 转换一个数字失败
ORA-6500            Storage-error                   内存不够引发的内部错误
ORA-6501            Program-error                  内部错误
ORA-6502            Value-error                      转换或截断错误
ORA-6511            Cursor-already-open          试图打开一个已存在的 游标
ORA-6530            Access-into-null                 试图为null 对象的属性赋值
3、非预定义异常
非预定义异常:在PL/SQL中还有一类会经常遇到的错误,每个错误都有相应的错误代码和错误原因,但是由于Oracle没有为这样的错误定义一个名称,因而不能直接进行异常处理。
在一般情况下,只能在PL/SQL块执行出错时查看其出错信息。
对于这类非预定义的异常,由于它也被自动抛出的,因而只需要定义一个异常,
把这个异常的名称与错误的代码关联起来,然后就可以像处理预定义异常那样处理这样的异常了。
 
在抛出ORACLE预定义异常之前先抛出自己定义的非预定义异常,可以大大节约异常定位的时间,
比如说很多情况都最终导致同一种预定义异常情况下。
4、用户自定义异常
用户自定义异常:程序员可以把一些特定的状态定义为异常。这样的异常一般由程序员自己决定,在一定的条件下抛出,然后利用PL/SQL的异常机制进行处理。
对于用户自定义的异常,有两种处理方法。
     第一种方法是先定义一个异常,并在适当的时候抛出,然后在PL/SQL块的异常处理部分进行处理。
          用户自定义的异常一般在一定的条件下抛出,于是这个条件就成为引发这个异常的原因。
     第二种方法是向调用者返回一个自定义的错误代码和一条错误信息。
          自定义错误代码的范围是-20000到-20999,是oracle为自定义错误保留的
          在处理用户自定义的异常时,也可以使用函数SQLCODE和SQLERRM,这两个函数分别用于返回指定的错误代码和错误信息。
5、系统预定义异常例子
DECLARE
  v_ename emp1.ename%TYPE;
  v_sal emp1.sal%TYPE;
BEGIN
  SELECT ename, sal
  INTO v_ename, v_sal
  FROM emp1;
  WHERE empno=9100;     --不存在的员工编号,会返回NO_DATA_FOUND异常
  DBMS_OUTPUT.PUT_LINE('ename is '||v_ename||'.');
  DBMS_OUTPUT.PUT_LINE('salary is '||v_sal||'.');
EXCEPTION
  WHEN NO_DATA_FOUND THEN     --无返回数据
    DBMS_OUTPUT.PUT_LINE('data not found.');
  WHEN TOO_MANY_ROWS THEN     --返回了多行数据
    DBMS_OUTPUT.PUT_LINE('exact fetch returns more than requested number of rows.');
  WHEN OTHERS THEN               --其他异常
    DBMS_OUTPUT.PUT_LINE('others exception.');
END;
 
OTHERS异常处理器能截获所有未经处理的异常,所以,OTHERS是最后定义的异常处理器。
6、非预定义异常例子
DECLARE
  emp_e  EXCEPTION;
  PRAGMA EXCEPTION_INIT (emp_e, -2292);          
          --EXCEPTION_INIT将异常名和一个系统错误代码联系起来    
  v_deptno   dept.deptno%TYPE := &p_deptno;
BEGIN
  DELETE FROM dept
  WHERE   deptno = v_deptno;
  --COMMIT;
EXCEPTION
  WHEN emp_e THEN
   DBMS_OUTPUT.PUT_LINE ('Cannot remove dept ' ||  
   TO_CHAR(v_deptno) || '.  Employees exist. ');
END;
 
ORA-02292: integrity constraint (string.string) violated - child record found
Cause:  attempted to delete a parent key value that had a foreign key dependency.
Action:  delete dependencies first then parent or disable constraint.8
7、使用错误函数(SQLCODE和SQLERRM)
例一、
DECLARE
  d_excep EXCEPTION;
  PRAGMA EXCEPTION_INIT (d_excep, -2292);
BEGIN
  DELETE FROM dept WHERE deptno=30;
EXCEPTION
  WHEN d_excep THEN
    DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/
例二、
先建立一个保存错误信息的表
CREATE TABLE u_err_table(
       username VARCHAR2(20),
       errdate DATE,
       errcode NUMBER,
       errm VARCHAR2(100)
       );
 
执行以下语句块,可能引发的异常交给OTHERS处理
DECLARE
  v_sqlcode NUMBER;
  v_sqlerrm VARCHAR2(100);
  v_deptno dept.deptno%TYPE := &deptno;
BEGIN
  DELETE FROM dept
  WHERE   deptno = v_deptno;
EXCEPTION
  WHEN OTHERS THEN
   v_sqlcode := SQLCODE;
   v_sqlerrm := SQLERRM;
   INSERT INTO u_err_table
   VALUES (USER, SYSDATE, v_sqlcode, v_sqlerrm);
END;
/
查看错误记录表:SELECT * FROM u_err_table;
8、用户自定义异常例子
在上面错误函数的例子里,如果输入一个不存在的部门号,程序并不会产生异常,就要用到用户自定义的异常来实现。
DECLARE
  e_err_deptno EXCEPTION;
     --定义异常
  v_deptno dept.deptno%TYPE := &deptno;
BEGIN
  DELETE FROM dept
  WHERE   deptno = v_deptno;
  IF SQL%NOTFOUND THEN
    RAISE e_err_deptno;
     --抛出异常
  END IF;
EXCEPTION
  WHEN e_err_deptno THEN
     --处理异常
   DBMS_OUTPUT.PUT_LINE('invalid deptno.');
END;
 
可以使用RAISE_APPLICATION_ERROR返回自定义的错误消息,看起来跟ORACLE的标准错误一样。
DECLARE
  v_sqlcode NUMBER;
  v_sqlerrm VARCHAR2(100);
  v_deptno dept.deptno%TYPE := &deptno;
BEGIN
  DELETE FROM dept
  WHERE   deptno = v_deptno;
  IF SQL%NOTFOUND THEN
    RAISE_APPLICATION_ERROR(-20001,'deptno not exists.');
  END IF;
EXCEPTION
  WHEN OTHERS THEN
   v_sqlcode := SQLCODE;
   v_sqlerrm := SQLERRM;
   DBMS_OUTPUT.PUT_LINE(v_sqlcode||': '||v_sqlerrm);
END;
 
自定义异常的例子:
DECLARE
  v_deptno  dept1.deptno%TYPE := &deptno;
  dd_exc    EXCEPTION;
BEGIN
  DELETE FROM dept1 WHERE deptno=v_deptno;
  IF SQL%NOTFOUND THEN
    RAISE dd_exc;
    ELSE
      dbms_output.put_line(SQL%ROWCOUNT||' rows deleted.');
  END IF;
EXCEPTION
  WHEN dd_exc THEN
    dbms_output.put_line('no rows deleted.');
END;
/


版权所有@北京神脑资讯技术有限公司(CUUG,中国UNIX用户协会) Copyright ALL Rights Reserved 京ICP备11008061号-1

CUUG旗下网站:www.cuug.com.cn www.cuug.com oracle.cuug.com bbs.cuug.com www.cuug.net

电话:010-59426307 010-59426319 邮政编码:100089

地址:北京市海淀区北清路164号28-38号院