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('No such customer!'); 
   WHEN others THEN 
      dbms_output.put_line('Error!'); 
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;  
   -- user defined exception 
   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 must be greater than zero!'); 
   WHEN no_data_found THEN 
      dbms_output.put_line('No such customer!'); 
   WHEN others THEN 
      dbms_output.put_line('Error!');  
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 当空对象自动分配值时引发。
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 当尝试执行不允许的游标操作(例如关闭未打开的游标)时引发。
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 当游标在具有不兼容数据类型的变量中获取值时引发。
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 当尝试将数字除以零时引发。
广告