异常处理 Oracle PL/SQL(示例)

PL/SQL 中的异常处理是什么?

当 PL/SQL 引擎遇到由于运行时发生的错误而无法执行的指令时,就会发生异常。这些错误不会在编译时被捕获,因此只需要在运行时处理。

例如,如果 PL/SQL 引擎收到一条指令,要求将任意数字除以“0”,则 PL/SQL 引擎会将其抛出为异常。PL/SQL 引擎只会在运行时引发该异常。

异常将停止程序的进一步执行,因此为了避免这种情况,需要捕获并单独处理它们。这个过程称为异常处理,程序员在此过程中处理运行时可能发生的异常。

异常处理语法

异常在块级别处理,即,一旦任何块中发生任何异常,控制权将脱离该块的执行部分。然后,异常将在该块的异常处理部分进行处理。处理异常后,无法将控制权重新发送回该块的执行部分。

以下语法解释了如何捕获和处理异常。

PL/SQL 中的异常处理

BEGIN
<execution block>
.
.
EXCEPTION
WHEN <exceptionl_name>
THEN
  <Exception handling code for the “exception 1 _name’' >
WHEN OTHERS
THEN
  <Default exception handling code for all exceptions >
END;

语法解释:

  • 在上面的语法中,异常处理块包含一系列 WHEN 条件来处理异常。
  • 每个 WHEN 条件后面都跟着预计在运行时引发的异常名称。
  • 当运行时出现任何异常时,PL/SQL 引擎将在异常处理部分中查找该特定异常。它将从第一个“WHEN”子句开始,然后按顺序进行搜索。
  • 如果它发现已引发异常的异常处理,那么它将执行该特定的处理代码部分。
  • 如果引发的异常没有“WHEN”子句,则 PL/SQL 引擎将执行“WHEN OTHERS”部分(如果存在)。这对于所有异常都是常见的。
  • 执行异常之后,部分控制将脱离当前块。
  • 运行时一个块只能执行一个异常部分,执行完该部分后,控制器将跳过剩余的异常处理部分,并退出当前块。

注: WHEN OTHERS 应始终位于序列的最后位置。WHEN OTHERS 之后的异常处理部分将永远不会执行,因为执行完 WHEN OTHERS 后,控制将退出该块。

异常类型

有两种类型的异常 数据库.

  1. 预定义异常
  2. 用户定义异常

预定义异常

Oracle 预定义了一些常见异常。这些异常具有唯一的异常名称和错误编号。这些异常已在“STANDARD”包中定义 Oracle在代码中我们可以直接使用这些预定义的异常名来处理它们。

以下是一些预定义的例外

特殊课程 错误代码 异常原因
访问空值 ORA-06530 为未初始化对象的属性赋值
未找到案例 ORA-06592 CASE 语句中的“WHEN”子句均不满足且未指定“ELSE”子句
集合 _ 为 _ NULL ORA-06531 使用集合方法(EXISTS 除外)或访问未初始化集合上的集合属性
光标已打开 ORA-06511 尝试打开 光标 已经打开了
索引上的重复值 ORA-00001 在受唯一索引约束的数据库列中存储重复值
无效光标 ORA-01001 非法游标操作,例如关闭未打开的游标
无效号码 ORA-01722 由于数字字符无效,字符转换为数字失败
没有找到数据 ORA-01403 当包含 INTO 子句的 'SELECT' 语句不获取任何行时。
行不匹配 ORA-06504 当游标变量数据类型与实际游标返回类型不兼容时
SUBSCRIPT_BEYOND_COUNT (订阅次数超过) ORA-06533 通过大于集合大小的索引号引用集合
订阅超出限制 ORA-06532 通过超出合法范围的索引号引用集合(例如:-1)
行数过多 ORA-01422 当带有 INTO 子句的 SELECT 语句返回多行时
值错误 ORA-06502 算术或大小约束错误(例如:为变量分配大于变量大小的值)
零除法 ORA-01476 将数字除以“0”

用户定义异常

In Oracle除了上述预定义的异常之外,程序员还可以创建自己的异常并进行处理。它们可以在声明部分中的子程序级别创建。这些异常仅在该子程序中可见。在包规范中定义的异常是公共异常,并且在可访问包的任何地方都可见。

语法: 在子程序级别

DECLARE
<exception_name> EXCEPTION; 
BEGIN
<Execution block>
EXCEPTION
WHEN <exception_name> THEN 
<Handler>
END;
  • 在上面的语法中,变量“exception_name”被定义为“EXCEPTION”类型。
  • 这可以以与预定义异常类似的方式使用。

语法:在封装规范级别

CREATE PACKAGE <package_name>
 IS
<exception_name> EXCEPTION;
.
.
END <package_name>;
  • 在上面的语法中,变量“exception_name”在包规范中定义为“EXCEPTION”类型。
  • 这可以在数据库中任何可以调用包“package_name”的地方使用。

PL/SQL 引发异常

所有预定义异常在发生错误时都会隐式引发。但用户定义的异常需要显式引发。这可以使用关键字“RAISE”来实现。这可以以下面提到的任何方式使用。

如果在程序中单独使用 'RAISE',那么它将把已经引发的异常传播到父块。只能在异常块中使用,如下所示。

PL/SQL 引发异常

CREATE [ PROCEDURE | FUNCTION ]
 AS
BEGIN
<Execution block>
EXCEPTION
WHEN <exception_name> THEN 
             <Handler>
RAISE;
END;

语法解释:

  • 在上面的语法中,关键字RAISE用于异常处理块中。
  • 每当程序遇到异常“exception_name”时,该异常都会被处理并正常完成
  • 但是异常处理部分的关键字‘RAISE’会将这个特定的异常传播到父程序。

注: 当向父块引发异常时,引发的异常也应该在父块中可见,否则 oracle 将引发错误。

  • 我们可以使用关键字“RAISE”后跟异常名称来引发特定的用户定义/预定义异常。这既可用于执行部分,也可用于异常处理部分来引发异常。

PL/SQL 引发异常

CREATE [ PROCEDURE | FUNCTION ] 
AS
BEGIN
<Execution block>
RAISE <exception_name>
EXCEPTION
WHEN <exception_name> THEN
<Handler>
END;

语法解释:

  • 在上面的语法中,执行部分使用了关键字RAISE,后面跟着异常“exception_name”。
  • 这将在执行时引发这个特定的异常,需要进一步处理或引发。

例子1:在这个例子中,我们将看到

  • 如何声明异常
  • 如何引发声明的异常以及
  • 如何传播到主区块

PL/SQL 引发异常

PL/SQL 引发异常

DECLARE
Sample_exception EXCEPTION;
PROCEDURE nested_block
IS
BEGIN
Dbms_output.put_line(‘Inside nested block’);
Dbms_output.put_line(‘Raising sample_exception from nested block’);
RAISE sample_exception;
EXCEPTION
WHEN sample_exception THEN 
Dbms_output.put_line (‘Exception captured in nested block. Raising to main block’);
RAISE,
END;
BEGIN
Dbms_output.put_line(‘Inside main block’);
Dbms_output.put_line(‘Calling nested block’);
Nested_block;
EXCEPTION
WHEN sample_exception THEN	
Dbms_output.put_line (‘Exception captured in main block');
END:
/

代码说明:

  • 代码行 2:将变量“sample_exception”声明为 EXCEPTION 类型。
  • 代码行 3:声明过程nested_block。
  • 代码行 6:打印语句“在嵌套块内”。
  • 代码第 7 行: 打印语句“从嵌套块中引发 sample_exception”。
  • 代码第 8 行: 使用“RAISE sample_exception”引发异常。
  • 代码第 10 行: 嵌套块中异常 sample_exception 的异常处理程序。
  • 代码第 11 行: 打印语句“在嵌套块中捕获异常。提升至主块”。
  • 代码第 12 行: 将异常引发到主块(传播到主块)。
  • 代码第 15 行: 打印语句“在主块内”。
  • 代码第 16 行: 打印语句“调用嵌套块”。
  • 代码第 17 行: 调用nested_block过程。
  • 代码第 18 行: 特殊课程
  • 代码第 19 行: 主块中 sample_exception 的异常处理程序。
  • 代码第 20 行: 打印语句“在主块中捕获异常”。

Exception 中需要注意的要点

  • 在函数中,异常应该始终返回值或进一步引发异常。else Oracle 将在运行时抛出‘函数返回时没有值’错误。
  • 可以在异常处理块中给出事务控制语句。
  • SQLERRM 和 SQLCODE 是内置函数,将提供异常消息和代码。
  • 如果未处理异常,则默认情况下该会话中的所有活动事务都将被回滚。
  • 引发应用程序错误 (- , ) 可代替 RAISE 来引发带有用户代码和消息的错误。错误代码应大于 20000 并以“-”为前缀。

结语

读完本章后,你应该能够完成 Pl 的以下几个方面 SQL 例外

  • 处理异常
  • 定义异常
  • 引发异常
  • 异常传播

总结一下这篇文章: