Oracle基础 PL-SQL编程基础(4) 异常处理

时间:2022-04-25 05:04:52

异常处理:

即使良好的PL-SQL程序也会遇到错误或者未预料的事件,一个优秀的程序都应该能够处理各种出错情况,尽可能的从错误中恢复。程序在运行时出现的错误成为异常。发生异常后,语句讲终止执行,PLSQL会立即将控制权交给PLSQL异常处理部分。Oracle中使用EXCEPTION来处理异常,一般有3种异常错误。

有三种类型的异常错误:

1. 预定义 ( Predefined )错误

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

2. 非预定义 ( Predefined )错误

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

3. 用户定义(User_define) 错误

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

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

语法:

EXCEPTION
   WHEN first_exception THEN  第一个异常处理的代码;
   WHEN second_exception THEN  第二个异常处理的代码
   WHEN OTHERS THEN  其他异常处理的代码
END;

1、预定义错误:

  由Oracle预先定义好的异常,Oracle中预定义的异常大约有24个。如下表所示。

错误号

异常错误信息名称

说明

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 索引得引用大于集合中元素的个数.

注意:预定义异常,首先是违背了 Oracle的规范,其次Oracle只为那20多个异常取了名字,如错误号"ORA-01043未找到数据"被命名为"NO_DATA_FOUND",这样在PLSQL中使用NO_DATA_FOUND来捕获处理就可以了。

示例:

DECLARE
V_ID NUMBER;
BEGIN
SELECT ID INTO v_id FROM es_user WHERE 1=0;
DBMS_OUTPUT.put_line(v_id);
EXCEPTION
WHEN too_many_rows THEN
DBMS_OUTPUT.put_line('无法将查询的多个值赋给变量');
WHEN no_data_found THEN
DBMS_OUTPUT.put_line('无法将空值付给变量');
WHEN OTHERS THEN
DBMS_OUTPUT.put_line('其他异常');
END;

如果查询语句返回多个结果,则会too_many_rows中的异常处理代码,如果没有值返回,则执行no_data_found异常处理的代码。如果发生其他错误,则执行others中的异常处理代码

2、非预定义错误

非预定义异常指其他标准的Oracle错误,对于这话总异常处理的情况,需要用户在程序中定义,然后由Oracle自动将其引发。

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

  (1)在PLSQL声明部分定义异常情况。

DECLARE
FK_EXCEPTION EXCEPTION; --定义一个异常

  (2)将其定义好的异常与标准的Oracle异常联系起来,使用EXCEPTION_INIT语句:

  PRAGMA EXCEPTION_INIT(FK_EXCEPTION,-2291);  --2291为Oracle定义的错误号,也就是违反了外键约束

  (3)在PLSQL中的异常处理部分对异常做出相应的处理。(完整代码)

DECLARE
FK_EXCEPTION EXCEPTION;
PRAGMA EXCEPTION_INIT(FK_EXCEPTION,-2291); --2291为Oracle定义的错误号,也就是违反了外键约束
BEGIN
UPDATE ES_ORDER SET user_id = 100 WHERE ID=1; --修改用户的ID为一个不存在的值,则会引发异常。
EXCEPTION
WHEN fk_exception THEN
DBMS_OUTPUT.put_line('该用户不存在');
END;

  非预定义异常同预定义异常一样,也是违背了Oracle的规范,但Oracle没有为这种异常取名字,如错误号"ORA-2291",没有名字,这样在PLSQL块的异常部分无法拨货,所以要预先定义异常变量。

3、用户自定义错误

程序执行过程中,出现了编程人员认为的非正常情况,对于这种异常情况,需要用户在程序中定义异常,然后显示的在程序中将其印发。用户自定义异常通过raise语句来触发。当引发这个异常,程序会专项EXCEPTION快处理异常。

对于这种异常处理,步骤如下:

  (1)在声明部分声明异常

DECLARE
AGE_EXCEPTION EXCEPTION; --声明一个异常

  (2)抛出异常信息

IF v_age < 0 OR v_age > 100 THEN
RAISE age_exception;
END IF;

  (3)在PLSQL异常处理部分对异常情况作出相应的处理。

EXCEPTION
WHEN age_exception THEN
DBMS_OUTPUT.put_line('年龄只能在0-100之间!');

示例:(判断年龄是否在0-100之间)

DECLARE
V_AGE NUMBER := &AGE;
AGE_EXCEPTION EXCEPTION;
BEGIN
IF v_age < 0 OR v_age > 100 THEN
RAISE age_exception;
END IF;
EXCEPTION
WHEN age_exception THEN
DBMS_OUTPUT.put_line('年龄只能在0-100之间!');
END;

异常存储过程:

除了以上3种异常处理,RAISE_APPLICATION_ERROR存储过程,可以重新定义异常错误消息,它为应用程序提供了一种与Oracle交互的方法。

语法:

  RAISE_APPLICATION_ERROR(error_number,error_message);

  error_number:表示用户为异常指定的编号,该编号必须是介于-20000~-20999之间的负整数。

  error_message:表示用户为异常指定的消息文本。消息长度可长达2048字节,错误消息是与error_number关联的文本。