PL/SQL - 异常
在本章中,我们将讨论 PL/SQL 中的异常。异常是在程序执行过程中发生的错误状况。PL/SQL 支持程序员使用程序中的 EXCEPTION 块捕获此类状况,并针对错误状况采取适当的行动。异常有两种类型 −
- 系统定义异常
- 用户定义异常
异常处理的语法
异常处理的一般语法如下。在此,您可以列出尽可能多的异常。默认异常将使用 WHEN others THEN 处理 −
DECLARE
<declarations section>
BEGIN
<executable command(s)>
EXCEPTION
<exception handling goes here >
WHEN exception1 THEN
exception1-handling-statements
WHEN exception2 THEN
exception2-handling-statements
WHEN exception3 THEN
exception3-handling-statements
........
WHEN others THEN
exception3-handling-statements
END;
示例
让我们编写一段代码来说明这个概念。我们将使用之前章节中创建和使用的 CUSTOMERS 表 −
DECLARE
c_id customers.id%type := 8;
c_name customerS.Name%type;
c_addr customers.address%type;
BEGIN
SELECT name, address INTO c_name, c_addr
FROM customers
WHERE id = c_id;
DBMS_OUTPUT.PUT_LINE ('Name: '|| c_name);
DBMS_OUTPUT.PUT_LINE ('Address: ' || c_addr);
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('没有这样的客户!');
WHEN others THEN
dbms_output.put_line('错误!');
END;
/
在 SQL 提示符下执行上述代码时,会产生以下结果 −
No such customer! PL/SQL procedure successfully completed.
上述程序显示给定 ID 的客户姓名和地址。由于数据库中没有 ID 为 8 的客户,程序引发运行时异常 NO_DATA_FOUND,该异常在 EXCEPTION 块 中被捕获。
引发异常
每当发生任何内部数据库错误时,数据库服务器会自动引发异常,但程序员也可以使用 RAISE 命令显式引发异常。引发异常的简单语法如下 −
DECLARE
exception_name EXCEPTION;
BEGIN
IF condition THEN
RAISE exception_name;
END IF;
EXCEPTION
WHEN exception_name THEN
statement;
END;
您可以使用上述语法引发 Oracle 标准异常或任何用户定义异常。在下一节中,我们将举例说明如何引发用户定义异常。您可以以类似方式引发 Oracle 标准异常。
用户定义异常
PL/SQL 允许您根据程序需求定义自己的异常。用户定义异常必须先声明,然后使用 RAISE 语句或过程 DBMS_STANDARD.RAISE_APPLICATION_ERROR 显式引发。
声明异常的语法如下 −
DECLARE my-exception EXCEPTION;
示例
以下示例说明了这个概念。该程序会提示输入客户 ID,当用户输入无效 ID 时,会引发异常 invalid_id。
DECLARE
c_id customers.id%type := &cc_id;
c_name customerS.Name%type;
c_addr customers.address%type;
-- 用户定义异常
ex_invalid_id EXCEPTION;
BEGIN
IF c_id <= 0 THEN
RAISE ex_invalid_id;
ELSE
SELECT name, address INTO c_name, c_addr
FROM customers
WHERE id = c_id;
DBMS_OUTPUT.PUT_LINE ('Name: '|| c_name);
DBMS_OUTPUT.PUT_LINE ('Address: ' || c_addr);
END IF;
EXCEPTION
WHEN ex_invalid_id THEN
dbms_output.put_line('ID 必须大于零!');
WHEN no_data_found THEN
dbms_output.put_line('没有找到这样的客户!');
WHEN others THEN
dbms_output.put_line('错误!');
END;
/
在 SQL 提示符下执行上述代码,将产生以下结果 −
Enter value for cc_id: -6 (let's enter a value -6) old 2: c_id customers.id%type := &cc_id; new 2: c_id customers.id%type := -6; ID must be greater than zero! PL/SQL procedure successfully completed.
预定义异常
PL/SQL 提供了许多预定义异常,当程序违反任何数据库规则时,这些异常会被执行。例如,当 SELECT INTO 语句没有返回行时,会引发预定义异常 NO_DATA_FOUND。下表列出了一些重要的预定义异常 −
| 异常名称 | Oracle 错误 | SQLCODE | 描述 |
|---|---|---|---|
| ACCESS_INTO_NULL | 06530 | -6530 | 当 null 对象被自动赋值为一个值时引发。 |
| CASE_NOT_FOUND | 06592 | -6592 | 当 CASE 语句的 WHEN 子句中没有选择任何选项,且没有 ELSE 子句时引发。 |
| COLLECTION_IS_NULL | 06531 | -6531 | 当程序尝试对未初始化的嵌套表或 varray 应用除 EXISTS 之外的集合方法,或者程序尝试为未初始化的嵌套表或 varray 的元素赋值时引发。 |
| DUP_VAL_ON_INDEX | 00001 | -1 | 当尝试在具有唯一索引的列中存储重复值时引发。 |
| INVALID_CURSOR | 01001 | -1001 | 当尝试执行不允许的 cursor 操作时引发,例如关闭一个未打开的 cursor。 |
| INVALID_NUMBER | 01722 | -1722 | 当将字符字符串转换为数字失败,因为该字符串不代表有效数字时引发。 |
| LOGIN_DENIED | 01017 | -1017 | 当程序尝试使用无效的用户名或密码登录数据库时引发。 |
| NO_DATA_FOUND | 01403 | +100 | 当 SELECT INTO 语句没有返回行时引发。 |
| NOT_LOGGED_ON | 01012 | -1012 | 当在未连接到数据库的情况下发出数据库调用时引发。 |
| PROGRAM_ERROR | 06501 | -6501 | 当 PL/SQL 出现内部问题时引发。 |
| ROWTYPE_MISMATCH | 06504 | -6504 | 当 cursor 获取的值与变量的数据类型不兼容时引发。 |
| SELF_IS_NULL | 30625 | -30625 | 当调用成员方法,但对象类型的实例未初始化时引发。 |
| STORAGE_ERROR | 06500 | -6500 | 当 PL/SQL 内存耗尽或内存损坏时引发。 |
| TOO_MANY_ROWS | 01422 | -1422 | 当 SELECT INTO 语句返回多于一行时引发。 |
| VALUE_ERROR | 06502 | -6502 | 当发生算术、转换、截断或大小约束错误时引发。 |
| ZERO_DIVIDE | 01476 | 1476 | 当尝试将一个数字除以零时引发。 |