Oracle 异常错误处理

即使是写得最好的PL/SQL程序也会遇到错误或未预料到的事件。

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

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

1.概念

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

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

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

DECLARE

BEGIN 

语句块;

EXCEPTION

WHEN first_exception THEN

WHEN second_exception THEN

WHEN OTHERS THEN

END;

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

有三种类型的异常错误:

1. 预定义( Predefined )错误

ORACLE预定义的异常情况大约有24个。对这种异常情况的处理,无需在程序中定义,由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索引得引用大于集合中元素的个数。

例子:

BEGIN

. . .

EXCEPTION

WHEN NO_DATA_FOUND THEN

statement1;

WHEN TOO_MANY_ROWS THEN

statement1;

WHEN OTHERS THEN

statement1;

statement2;

END;

OTHERS的处理: Others表明我们程序员未能预计到这种错误,所以全部归入到others 里面去了,单发生这种

情况是,我们还是希望了解当时发生的Oracle错误号和相关描述信息,怎样才能取到呢?

Oracle 提供了两个内置函数 SQLCODE SQLERRM 分别用来返回Oracle 错误号和错误描述

DECLARE

v_error_code NUMBER;

v_error_message VARCHAR2(255);

BEGIN

...

EXCEPTION

...

WHEN OTHERS THEN

ROLLBACK;

v_error_code := SQLCODE ;

v_error_message := SQLERRM ;

INSERT INTO errors

VALUES(v_error_code, v_error_message);

END;

2. 非预定义( Predefined )错误

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

处理非预定义的Oracle错误:此类错误属于Oracle错误,有编号,但无错误名称定义,使用时需要先声明,并

进行错误初始化:



DEFINE p_deptno = 10

DECLARE

e_emps_remaining EXCEPTION;

PRAGMA EXCEPTION_INIT

(e_emps_remaining, -2292);

BEGIN

DELETE FROM departments

WHERE department_id = &p_deptno;

COMMIT;

EXCEPTION

WHEN e_emps_remaining THEN

DBMS_OUTPUT.PUT_LINE ('Cannot remove dept ' ||

TO_CHAR(&p_deptno) || '. Employees exist. ');

END;

3. 用户定义(User_define)错误

处理非预定义的Oracle错误:此类错误属于Oracle错误,有编号,但无错误名称定义,使用时需要先声明,并

进行错误初始化:

例子:

DEFINE p_deptno = 10

DECLARE

e_emps_remaining EXCEPTION;

PRAGMA EXCEPTION_INIT

(e_emps_remaining, -2292);

BEGIN

DELETE FROM departments

WHERE department_id = &p_deptno;

COMMIT;

EXCEPTION

WHEN e_emps_remaining THEN

DBMS_OUTPUT.PUT_LINE ('Cannot remove dept ' ||

TO_CHAR(&p_deptno) || '. Employees exist. ');

END;

4.RAISE_APPLICATION_ERROR() 函数

对于用户自定义的业务错误,如果觉得先定义再使用很麻烦,那么

也可以简单的使用raise_application_error() 来简化处理。它可以无需预先定义错误,而在需要抛出错误的

地方直接使用此函数抛出例外,例外可以包含用户自定义的错误吗和错误描述;

BEGIN

...

DELETE FROM employees

WHERE manager_id = v_mgr;

IF SQL%NOTFOUND THEN

RAISE_APPLICATION_ERROR(-20202,

'This is not a valid manager');

END IF;

...

...

EXCEPTION

WHEN NO_DATA_FOUND THEN

RAISE_APPLICATION_ERROR (-20201,

'Manager is not a valid employee.');

END;

5.运行时异常,业务异常整合

create or replace package sys_raise_app_error_pkg is

  -- Author  : CZH

  -- Created : 2020/8/1 10:21:30

  -- Purpose : 异常处理(运行时异常,业务异常)

  procedure is_running_error(p_err_msg          in varchar2 default null,

                            p_is_running_error in varchar2);

end sys_raise_app_error_pkg;

/

create or replace package body sys_raise_app_error_pkg is

  /*============================================*

  * Author  : SANFU

  * Created  : 2020-08-01 15:18:15

  * ALERTER  :

  * ALERTER_TIME  :

  * Purpose  : 异常处理

  * Obj_Name    : IS_RUNNING_ERROR

  * Arg_Number  : 2

  * X_MESSAGE :错误消息

  * P_IS_RUNNING_ERROR :(T:运行时异常,F:业务提示)

  *============================================*/

  procedure is_running_error(p_err_msg          in varchar2 default null,

                            p_is_running_error in varchar2) is


    v_error_type varchar2(100);

    --v_err_msg    varchar2(1000);

    running_error_exp    exception;

    not_running_error_exp exception;

    error_msg_rec nbw.sys_app_error_msg%rowtype;

  begin


    if 'T' = p_is_running_error then

      v_error_type := '系统报错(Oracle 异常)';

      raise running_error_exp;

    elsif 'F' = p_is_running_error then

      v_error_type := '业务提示';

      raise not_running_error_exp;

    end if;


    error_msg_rec.error_type := v_error_type;


  exception


    when not_running_error_exp then


      error_msg_rec.error_id      := nbw.SYS_APP_ERROR_MSG_S.NEXTVAL;

      error_msg_rec.error_line_num := dbms_utility.format_error_backtrace;

      --业务异常,可自行编写提示信息 

      error_msg_rec.error_msg := nvl(p_err_msg,

                                    dbms_utility.format_error_stack);


      /*      if p_err_msg is null then

        v_err_msg := error_msg_rec.error_msg;

      end if;*/

      --插入到错误信息表,记录日志

      insert into nbw.SYS_APP_ERROR_MSG

        (ERROR_ID, ERROR_TYPE, ERROR_LINE_NUM, ERROR_MSG, CREATE_TIME)

      values

        (error_msg_rec.error_id,

        error_msg_rec.error_type,

        error_msg_rec.error_line_num,

        error_msg_rec.error_msg,

        sysdate);

      commit;

      raise_application_error(-20002,

                              v_error_type || ':' ||

                              error_msg_rec.error_msg);


    when running_error_exp then


      error_msg_rec.error_id      := nbw.SYS_APP_ERROR_MSG_S.NEXTVAL;

      error_msg_rec.error_line_num := dbms_utility.format_error_backtrace;

      error_msg_rec.error_msg      := nvl(p_err_msg,

                                          dbms_utility.format_error_stack);


      /*      if p_err_msg is null then

        v_err_msg := error_msg_rec.error_msg;

      end if;*/

      --插入到错误信息表,记录日志

      insert into nbw.SYS_APP_ERROR_MSG

        (ERROR_ID, ERROR_TYPE, ERROR_LINE_NUM, ERROR_MSG, CREATE_TIME)

      values

        (error_msg_rec.error_id,

        error_msg_rec.error_type,

        error_msg_rec.error_line_num,

        error_msg_rec.error_msg,

        sysdate);

      commit;

      raise_application_error(-20002,

                              v_error_type || ',' || '请联系平台管理员!!' ||

                              '错误编号:' || error_msg_rec.error_id);

  end is_running_error;

end sys_raise_app_error_pkg;

/

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容