本文转自:http://www.cnblogs.com/soundcode/archive/2012/01/10/2318385.html

本篇主要内容如下:

5.1 异常处理概念

5.1.1 预定义的异常处理

5.1.2 非预定义的异常处理

5.1.3 用户自定义的异常处理

5.1.4  用户定义的异常处理

5.2 异常错误传播

5.2.1 在执行部分引发异常错误

5.2.2 在声明部分引发异常错误

5.3 异常错误处理编程

5.4  在 PL/SQL 中使用 SQLCODE, SQLERRM异常处理函数


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

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

5.1 异常处理概念

异常情况处理(EXCEPTION)是用来处理正常执行过程中未预料的事件,程序块的异常处理预定义的错误和自定义错误,由于PL/SQL程序块一旦产生异常而没有指出如何处理时,程序就会自动终止整个程序运行.

有三种类型的异常错误:

1. 预定义 ( Predefined )错误

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

2. 非预定义 ( Predefined )错误

即其他标准的ORACLE错误。对这种异常情况的处理,需要用户在程序中定义,然后由ORACLE自动将其引发。

3. 用户定义(User_define) 错误

程序执行过程中,出现编程人员认为的非正常情况。对这种异常情况的处理,需要用户在程序中定义,然后显式地在程序中将其引发。

异常处理部分一般放在 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 > END;

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

5.1.1 预定义的异常处理

预定义说明的部分 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

SELECT INTO没有找到数据

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-6504

Rowtype-mismatch

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

ORA-6511

CURSOR-already-OPEN

试图打开一个已处于打开状态的游标

ORA-6530

Access-INTO-null

试图为null 对象的属性赋值

ORA-6531

Collection-is-null

试图将Exists 以外的集合( collection)方法应用于一个null pl/sql 表上或varray上

ORA-6532

Subscript-outside-limit

对嵌套或varray索引得引用超出声明范围以外

ORA-6533

Subscript-beyond-count

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

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

例1:更新指定员工工资,如工资小于1500,则加100;


DECLARE    v_empno employees.employee_id%TYPE := &empno;    v_sal   employees.salary%TYPE; BEGIN    SELECT salary INTO v_sal FROM employees WHERE employee_id = v_empno;    IF v_sal<=1500 THEN         UPDATE employees SET salary = salary + 100 WHERE employee_id=v_empno;         DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'员工工资已更新!');        ELSE         DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'员工工资已经超过规定值!');    END IF; EXCEPTION    WHEN NO_DATA_FOUND THEN        DBMS_OUTPUT.PUT_LINE('数据库中没有编码为'||v_empno||'的员工');    WHEN TOO_MANY_ROWS THEN       DBMS_OUTPUT.PUT_LINE('程序运行错误!请使用游标');    WHEN OTHERS THEN       DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM); END;

5.1.2 非预定义的异常处理

对于这类异常情况的处理,首先必须对非定义的ORACLE错误进行定义。步骤如下:

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

<异常情况>  EXCEPTION;

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

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

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

例2:删除指定部门的记录信息,以确保该部门没有员工。


INSERT INTO departments VALUES(50, 'FINANCE', 'CHICAGO');
DECLARE    v_deptno departments.department_id%TYPE := &deptno;    deptno_remaining EXCEPTION;    PRAGMA EXCEPTION_INIT(deptno_remaining, -2292);    /* -2292 是违反一致性约束的错误代码 */ BEGIN    DELETE FROM departments WHERE department_id = v_deptno; EXCEPTION    WHEN deptno_remaining THEN       DBMS_OUTPUT.PUT_LINE('违反数据完整性约束!');    WHEN OTHERS THEN       DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM); END;

5.1.3 用户自定义的异常处理

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

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

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

<异常情况>  EXCEPTION;

2. RAISE <异常情况>;

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

例3:更新指定员工工资,增加100;


DECLARE    v_empno employees.employee_id%TYPE :=&empno;    no_result  EXCEPTION; BEGIN    UPDATE employees SET salary = salary+100 WHERE employee_id = v_empno;    IF SQL%NOTFOUND THEN       RAISE no_result;    END IF; EXCEPTION    WHEN no_result THEN        DBMS_OUTPUT.PUT_LINE('你的数据更新语句失败了!');    WHEN OTHERS THEN       DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM); END;

5.1.4  用户定义的异常处理

调用DBMS_STANDARD(ORACLE提供的包)包所定义的RAISE_APPLICATION_ERROR过程,可以重新定义异常错误消息,它为应用程序提供了一种与ORACLE交互的方法。

RAISE_APPLICATION_ERROR 的语法如下:

    RAISE_APPLICATION_ERROR(error_number,error_message,[keep_errors] );

这里的error_number 是从 –20,000 到 –20,999 之间的参数,

error_message 是相应的提示信息(< 2048 字节),

keep_errors 为可选,如果keep_errors =TRUE ,则新错误将被添加到已经引发的错误列表中。如果keep_errors=FALSE(缺省),则新错误将替换当前的错误列表。

例4:创建一个函数get_salary, 该函数检索指定部门的工资总和,其中定义了-20991和-20992号错误,分别处理参数为空和非法部门代码两种错误:


CREATE TABLE errlog(   Errcode NUMBER,   Errtext CHAR(40));
CREATE OR REPLACE FUNCTION get_salary(p_deptno NUMBER) RETURN NUMBER AS   v_sal NUMBER; BEGIN   IF p_deptno IS NULL THEN     RAISE_APPLICATION_ERROR(-20991, ’部门代码为空’);   ELSIF p_deptno<0 THEN     RAISE_APPLICATION_ERROR(-20992, ’无效的部门代码’);   ELSE     SELECT SUM(employees.salary) INTO v_sal FROM employees     WHERE employees.department_id=p_deptno;     RETURN v_sal;   END IF; END;
DECLARE   V_salary NUMBER(7,2);   V_sqlcode NUMBER;   V_sqlerr VARCHAR2(512);   Null_deptno EXCEPTION;   Invalid_deptno EXCEPTION;   PRAGMA EXCEPTION_INIT(null_deptno,-20991);   PRAGMA EXCEPTION_INIT(invalid_deptno, -20992); BEGIN   V_salary :=get_salary(10);   DBMS_OUTPUT.PUT_LINE('10号部门工资:' || TO_CHAR(V_salary));
  BEGIN     V_salary :=get_salary(-10);   EXCEPTION     WHEN invalid_deptno THEN       V_sqlcode :=SQLCODE;       V_sqlerr  :=SQLERRM;       INSERT INTO errlog(errcode, errtext)       VALUES(v_sqlcode, v_sqlerr);       COMMIT;   END inner1;
  V_salary :=get_salary(20);   DBMS_OUTPUT.PUT_LINE('部门号为20的工资为:'||TO_CHAR(V_salary));
  BEGIN     V_salary :=get_salary(NULL);   END inner2;
  V_salary := get_salary(30);   DBMS_OUTPUT.PUT_LINE('部门号为30的工资为:'||TO_CHAR(V_salary));
  EXCEPTION     WHEN null_deptno THEN       V_sqlcode :=SQLCODE;       V_sqlerr  :=SQLERRM;       INSERT INTO errlog(errcode, errtext) VALUES(v_sqlcode, v_sqlerr);       COMMIT;     WHEN OTHERS THEN          DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM); END outer;

例5:定义触发器,使用RAISE_APPLICATION_ERROR阻止没有员工姓名的新员式记录插入:


CREATE OR REPLACE TRIGGER tr_insert_emp BEFORE INSERT ON employees FOR EACH ROW BEGIN   IF :new.first_name IS NULL OR :new.last_name is null THEN     RAISE_APPLICATION_ERROR(-20000,'Employee must have a name.');   END IF; END;

5.2 异常错误传播

由于异常错误可以在声明部分和执行部分以及异常错误部分出现,因而在不同部分引发的异常错误也不一样。

5.2.1 在执行部分引发异常错误

当一个异常错误在执行部分引发时,有下列情况:

l 如果当前块对该异常错误设置了处理,则执行它并成功完成该块的执行,然后控制转给包含块。

l 如果没有对当前块异常错误设置定义处理器,则通过在包含块中引发它来传播异常错误。然后对该包含块执行步骤1)。

5.2.2 在声明部分引发异常错误

如果在声明部分引起异常情况,即在声明部分出现错误,那么该错误就能影响到其它的块。比如在有如下的PL/SQL程序:


DECLARE     name varchar2(12):='EricHu';     其它语句 BEGIN     其它语句 EXCEPTION     WHEN OTHERS THEN      其它语句 END;

例子中,由于Abc number(3)=’abc’; 出错,尽管在EXCEPTION中说明了WHEN OTHERS THEN语句,但WHEN OTHERS THEN也不会被执行。 但是如果在该错误语句块的外部有一个异常错误,则该错误能被抓住,如:


BEGIN     DECLARE     name varchar2(12):='EricHu';     其它语句    BEGIN     其它语句    EXCEPTION     WHEN OTHERS THEN      其它语句     END; EXCEPTION WHEN OTHERS THEN      其它语句 END;

5.3 异常错误处理编程

在一般的应用处理中,建议程序人员要用异常处理,因为如果程序中不声明任何异常处理,则在程序运行出错时,程序就被终止,并且也不提示任何信息。下面是使用系统提供的异常来编程的例子。

5.4  在 PL/SQL 中使用 SQLCODE, SQLERRM异常处理函数

由于ORACLE 的错信息最大长度是512字节,为了得到完整的错误提示信息,我们可用 SQLERRM和 SUBSTR 函数一起得到错误提示信息,方便进行错误,特别是如果WHEN OTHERS异常处理器时更为方便。

SQLCODE  返回遇到的Oracle错误号,

SQLERRM  返回遇到的Oracle错误信息.

如:  SQLCODE=-100   è SQLERRM=’no_data_found ‘

SQLCODE=0      è SQLERRM=’normal, successfual completion’

例6. 将ORACLE错误代码及其信息存入错误代码表


CREATE TABLE errors (errnum NUMBER(4), errmsg VARCHAR2(100));
DECLARE    err_msg  VARCHAR2(100); BEGIN    /*  得到所有 ORACLE 错误信息  */    FOR err_num IN -100 .. 0 LOOP       err_msg := SQLERRM(err_num);       INSERT INTO errors VALUES(err_num, err_msg);    END LOOP; END; DROP TABLE errors;

例7. 查询ORACLE错误代码;


BEGIN    INSERT INTO employees(employee_id, first_name,last_name,hire_date,department_id)    VALUES(2222, 'Eric','Hu', SYSDATE, 20);    DBMS_OUTPUT.PUT_LINE('插入数据记录成功!');        INSERT INTO employees(employee_id, first_name,last_name,hire_date,department_id)    VALUES(2222, '胡','勇', SYSDATE, 20);    DBMS_OUTPUT.PUT_LINE('插入数据记录成功!'); EXCEPTION    WHEN OTHERS THEN       DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM); END;

例8. 利用ORACLE错误代码,编写异常错误处理代码;


DECLARE    empno_remaining EXCEPTION;    PRAGMA EXCEPTION_INIT(empno_remaining, -1);    /* -1 是违反唯一约束条件的错误代码 */ BEGIN    INSERT INTO employees(employee_id, first_name,last_name,hire_date,department_id)    VALUES(3333, 'Eric','Hu', SYSDATE, 20);    DBMS_OUTPUT.PUT_LINE('插入数据记录成功!');        INSERT INTO employees(employee_id, first_name,last_name,hire_date,department_id)    VALUES(3333, '胡','勇',SYSDATE, 20);    DBMS_OUTPUT.PUT_LINE('插入数据记录成功!'); EXCEPTION    WHEN empno_remaining THEN        DBMS_OUTPUT.PUT_LINE('违反数据完整性约束!');    WHEN OTHERS THEN       DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM); END;

© 2011  EricHu

原创作品,转贴请注明作者和出处,留此信息。

------------------------------------------------

cnBlobs:http://www.cnblogs.com/huyong/CSDN:http://blog.csdn.net/chinahuyong

作者:EricHu(DB、C\S、B\S、WebService、WCF、PM等) 出处:http://www.cnblogs.com/huyong/

Q Q:80368704   E-Mail: 80368704@qq.com 本博文欢迎大家浏览和转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,在『参考』的文章中,我会表明参考的文章来源,尊重他人版权。若您发现我侵犯了您的版权,请及时与我联系。 更多文章请看[置顶]索引贴——(不断更新中)

[转]ORACLE 异常错误处理的更多相关文章

  1. 总结:整理 oracle异常错误处理 .

    5.1 异常处理概念 5.1.1 预定义的异常处理 5.1.2 非预定义的异常处理 5.1.3 用户自定义的异常处理 5.1.4  用户定义的异常处理 5.2 异常错误传播 5.2.1 在执行部分引发 ...

  2. 整理 oracle异常错误处理

    5.1 异常处理概念 5.1.1 预定义的异常处理 5.1.2 非预定义的异常处理 5.1.3 用户自定义的异常处理 5.1.4  用户定义的异常处理 5.2 异常错误传播 5.2.1 在执行部分引发 ...

  3. oracle 异常错误处理

    分类: Oracle 5.1 异常处理概念 5.1.1 预定义的异常处理 5.1.2 非预定义的异常处理 5.1.3 用户自定义的异常处理 5.1.4 用户定义的异常处理 5.2 异常错误传播 5.2 ...

  4. [推荐]ORACLE PL/SQL编程之五:异常错误处理(知已知彼、百战不殆)

    原文:[推荐]ORACLE PL/SQL编程之五:异常错误处理(知已知彼.百战不殆) [推荐]ORACLE PL/SQL编程之五: 异常错误处理(知已知彼.百战不殆) 继上三篇:ORACLE PL/S ...

  5. oracle 异常

    ORACLE 异常错误处理 本篇主要内容如下: 5.1 异常处理概念 5.1.1 预定义的异常处理 5.1.2 非预定义的异常处理 5.1.3 用户自定义的异常处理 5.1.4  用户定义的异常处理 ...

  6. oracle有三种类型的异常错误: 预定义 ( Predefined )错误里面的常见错误

    oracle有三种类型的异常错误: 预定义 ( Predefined )错误, 非预定义 ( Predefined )错误, 用户定义(User_define) 错误 预定义 ( Predefined ...

  7. Oracle异常汇总

    持续更新中,可参见https://hnuhell.gitbooks.io/oracle_errmg/content/或https://hnuhell.github.io/Oracle_ERRMG/上的 ...

  8. ORACLE异常(整理网上资料)

    一.oracle预定义异常 命名的系统异常 产生原因 Oracle Error SQLCODE Value ACCESS_INTO_NULL 未定义对象 ORA-06530  -6530 CASE_N ...

  9. oracle数据库-错误编码大全

    ORA-00001: 违反唯一约束条件 (.) ORA-00017: 请求会话以设置跟踪事件   ORA-00018: 超出最大会话数   ORA-00019: 超出最大会话许可数   ORA-000 ...

随机推荐

  1. Velocity - 单例还是非单例

    在Velocity1.2版本以后,开发者现在又两种选择来使用Velocity引擎,单例模型(singleton model)和单独实例模型(separate instance model).这是相同的 ...

  2. js实现收缩菜单效果

    废话不多说,直接上代码: 有注释 <head> <title></title> <style type="text/css"> di ...

  3. class0513(html基础加强)

    内容:HTML.CSS 目标:掌握手写HTML实现一般难度的Web页面的能力(如网站注册表单),为ASP.Net学习打基础.坚持手写HTML,可视化设计只是一种自学的手段. 参考书:张孝祥<Ja ...

  4. i++ 和 ++i 效率的分析

    我们通常在写for循环 的时候,要实现变量 i 的自增 1 :往往会在i++ 和++i中随便挑一种写,对于i++和++i的理解,我们往往停留在返回的值的不同,其实i++与++i在实现效率上也有一定的不 ...

  5. 【转载】linux命令行计算器bc的一个“坑”

    [转载自]http://blog.chinaunix.net/uid-174325-id-3518953.html 结论:ibase,obase可以使用在不同的计算公式里,但是尽量把obase放iba ...

  6. 将COleDateTime类型数据转换成char *数据

    用OpenCV做多摄像头校准时间,在图像上显示时间信息,需求要将COleDateTime类型数据转换成char *数据 具体代码如下: 1: COleDateTime m_checkDate; 2: ...

  7. leetcode@ [173] Binary Search Tree Iterator (InOrder traversal)

    https://leetcode.com/problems/binary-search-tree-iterator/ Implement an iterator over a binary searc ...

  8. Android权威编程指南读书笔记(1-2章)

    第一章 Android应用初体验 1.4用户界面设计 <?xml version="1.0" encoding="utf-8"?> ADT21开发版 ...

  9. Android实例-从照相机或图库获取照片(XE8+小米2)

    结果: 1.如果要取本地相册的话,小米手机要注意一下,不能取网络相册. 操作: 1.两个 TButton (Button1 和 Button2) , 一个 TActionList(ActionList ...

  10. [iOS基础控件 - 6.4] 汽车品牌展示 Model嵌套/KVC/TableView索引

    A.需求 1.使用汽车品牌名称头字母为一个Model,汽车品牌为一个Model,头字母Model嵌套品牌Model 2.使用KVC进行Model封装赋值 3.展示头字母标题 4.展示索引(使用KVC代 ...