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

PL/SQL 中的异常处理是什么?
当PL/SQL引擎遇到由于运行时错误而无法执行的指令时,就会发生异常。这些错误在编译时无法检测到,因此只能在运行时处理。
例如,如果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 执行完毕后,控制权就会离开该代码块。
异常类型
例外情况有两种类型 PL / SQL.
- 预定义异常
- 用户定义的异常
预定义异常
Oracle 预定义了一些常见的异常。每个预定义的异常都有一个唯一的名称和错误编号,所有这些异常都在 STANDARD 包中声明。 Oracle在代码中,您可以直接使用这些预定义的异常名称来处理相应的错误。其中许多异常名称直接映射到常见的异常类型。 SQL 你每天都会遇到的错误。
以下是一些预先设定的例外情况:
| 特殊课程 | 误差 Code | 异常原因 |
|---|---|---|
| 访问空值 | 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 | 除以零 |
用户定义异常
除了上述预定义的异常之外,程序员还可以创建和处理自定义异常。自定义异常在子程序级别的声明部分创建,并且仅在该子程序内部可见。在包规范中定义的异常是公共异常,在任何可以访问该包的地方都可见。
语法:在子程序级别
DECLARE <exception_name> EXCEPTION; BEGIN <Execution block> EXCEPTION WHEN <exception_name> THEN <Handler> END;
- 在上面的语法中,变量“exception_name”被定义为异常类型。
- 然后,它可以像预定义异常一样使用。
语法:在包规范级别
CREATE PACKAGE <package_name> IS <exception_name> EXCEPTION; . . END <package_name>;
- 在上面的语法中,变量“exception_name”被定义为包规范中的异常类型。 。
- 它可以在数据库中任何可以调用包名“package_name”的地方使用。
PL/SQL 引发异常
所有预定义的异常都会在发生相应错误时隐式抛出。但是,用户自定义的异常必须使用关键字 RAISE 显式抛出。RAISE 的用法如下所示。
如果在处理程序中单独使用 RAISE,它会将已引发的异常传播到父代码块。它只能在异常处理代码块中使用,如下所示。
下面的屏幕截图显示了单独使用 RAISE 来重新向封闭代码块抛出异常的情况:
CREATE [ PROCEDURE | FUNCTION ] AS BEGIN <Execution block> EXCEPTION WHEN <exception_name> THEN <Handler> RAISE; END;
语法解释:
- 在上面的语法中,关键字 RAISE 用于异常处理块内。
- 每当程序遇到异常“exception_name”时,都会处理该异常并正常完成。
- 处理程序中的关键字 RAISE 会将相同的异常传播到父程序。
注意: 当向父代码块抛出异常时,抛出的异常也必须在父代码块中可见;否则 Oracle 引发错误。
您还可以使用关键字 RAISE 后跟异常名称来引发特定的用户定义或预定义异常。这种形式既可用于执行部分,也可用于异常处理部分。
下面的屏幕截图显示了 RAISE 命令,后跟异常名称,用于引发特定异常:
CREATE [ PROCEDURE | FUNCTION ] AS BEGIN <Execution block> RAISE <exception_name> EXCEPTION WHEN <exception_name> THEN <Handler> END;
语法解释:
- 在上面的语法中,关键字 RAISE 用于执行部分,后面跟着异常“exception_name”。
- 这会在运行时引发该特定异常,然后需要对其进行处理或进一步引发。
例如1: 在这个例子中,我们将看到:
- 如何声明异常
- 如何引发已声明的异常
- 如何传播到主区块
下面的屏幕截图显示了完整的代码块,该代码块声明了 sample_exception,在嵌套代码块中引发了该异常,并将其传播到主代码块:
以下截图展示了相同示例的后续部分,其中主代码块最终捕获了传播的异常:
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; /
Code 说明:
- Code 第2行: 将变量“sample_exception”声明为 EXCEPTION 类型。
- Code 第3行: 声明过程 nested_block。
- Code 第6行: 打印语句“嵌套块内”。
- Code 第7行: 打印语句“从嵌套块引发 sample_exception”。
- Code 第8行: 使用“RAISE sample_exception”引发异常。
- Code 第10行: 嵌套块中异常 sample_exception 的异常处理程序。
- Code 第11行: 打印语句“嵌套代码块中捕获到异常。将异常抛出到主代码块”。
- Code 第12行: 将异常抛出到主代码块(传播异常)。
- Code 第15行: 打印语句“在主块内”。
- Code 第16行: 打印语句“调用嵌套块”。
- Code 第17行: 调用 nested_block 过程。
- Code 第19行: 主块中 sample_exception 的异常处理程序。
- Code 第20行: 打印语句“主代码块中捕获到异常”。
Exception 中需要注意的要点
- 在函数中,异常要么应该返回一个值,要么应该进一步抛出异常;否则 Oracle 运行时抛出“函数返回时没有值”错误。
- 交易控制声明 可以在异常处理块内发出。
- SQLERRM 和 SQLCODE 是内置函数,分别返回异常消息和异常代码。
- 如果未处理异常,则默认情况下该会话中的所有活动事务都会回滚。
- RAISE_APPLICATION_ERROR (- ,可以使用 `)` 代替 `RAISE` 来引发带有自定义代码和消息的错误。错误代码必须介于 -20000 和 -20999 之间。





