Oracle PL/SQL 程序设计读书笔记 - 第6章 异常处理
Oracle PL/SQL 程序设计读书笔记 - 第6章 异常处理
6.1 异常处理概念和术语
- 系统异常:这是由Oracle定义 的,在PL/SQL运行时引擎 发现某个错误 后招抛出来的异常。某些系统异常有名称 ,比如NODATAFOUND,更多的异常公有一个数字 和描述。
- 程序员定义的异常:这是由程序员定义的异常,并且专门针对当前的应用程序设计。你可以使用EXCEPTIONINIT指令给Oracle错误指定名称,或者使用RAISEAPPLICATION_ERROR给这个错误指定一个数字和描述。
- 无名或者匿名异常:有些异常只有一个错误代码和描述,没有可用于RAISE语句或者异常处理WHEN语句中的名称。
- 有名的异常:一个Oracle的内置包或者由开发人员命名。也可以通过EXCEPTION_INIT编译指令为异常分配一个名字,或者只定义一个名字(名字可以 用在RAISE和异常处理部分)
6.2 定义异常
PL/SQL的两个缺省包之一,STANDARD包和DBMS_STANDARD包。
6.2.1 声明有名异常
你必须 在PL/SQL代码块的声明部分自己声明这些异常。声明异常的方法是在程序中列出异常的名称,后面再跟上关键词EXCEPTION,像这样
PROCEDURE XXX
IS
invalid_company_id EXCEPTION;
BEGIN
.... body of excutable statements ...
EXCEPTION
WHEN NO_DATA_FOUND -- system exception
THEN
...
WHEN invalid_company_id
THEN
...
END;
异常的名字在格式上非常类型布尔类型变量名,但是有两种引用方式。 * 在程序的执行单元 中的RAISE语句引用(抛出异常)
RAISE xxx_exception;
-
在异常处理单元的WHEN语句(处理招聘的异常时)
WHEN xxx_exception THEN
6.2.2 异常名称和错误代码相互关联
错误数字是在-20000和-20999之间的数字。没有名字的异常是完全合法的。 SQLCODE是一个内置函数,使用是返回最后抛出错误,。
-
使用EXCEPTIONINIT EXCEPTIONINIT指令会让编译器把那个用EXCEPTION定义的标识符和一个指定的错误数字关联到一起。一旦创建了这个关联关系,你就可以通过名字来抛出异常,也可以 用名字写一个明确的WHEN处理句柄来捕获这个错误。 EXCEPTION_INIT编译指令必须出现在代码块的声明单元,并且该异常已经在同一个块中或外层块,或者包的规范部分被命名了。这是一个匿名块的语法:
DECLARE exceptionname EXCEPTION; PRAGMA EXCEPTIONINIT(exception_name, integer);
这里的exception_name就是异常的名称,integer是一个整数值。也就是要关联到这个被命名异常的Oracle错误号。错误数字可以使用符合下列约束的任意整数: 不可以使用-1403。若因为某些原因要把自己命名的异常关联到这个错误,你需要给EXCEPTION_INIT指令传递100 不可以使用除了0和100之外的任何正数 * 不可以使用小于-1000000的负数。
建议以下两种场合使用EXCEPTION_INIT指令 为一些程序中经常要用到的,匿名的系统异常命名。 为使用RAISE-APPLICATION_ERROR抛出的应用专有错误命名。
6.2.4 异常的作用范围
- 被命名的系统异常:这些异常不是在某个专门的代码块中声明或定义的,是全局都可用的。可以在任何代码中抛出和处理被命名的系统异常。
- 被命名的程序定义的异常:这种异常只能在声明它的块的执行单元异常处理单元被抛出和处理。对于在包规范部分定义的异常,那么对于那些对这个包具有的EXECUTE权限的用户的程序,这个异常都是可见的
- 匿名系统异常:这些任何PL/SQL块的异常处理单元的WHEN OTHERS部分处理。如果这些已成被指定了名字,这个名称的作用范围是和被命名的自定义异常是一样的。
- 匿名的自定义异常:这些异常只是在调用 RAISEAPPLICATIONERROR时才定义,并返回到调用程序。
6.3 抛出异常
程序中可以有3种抛出异常的办法 数据库检测到错误时可以抛出异常 使用RAISE语句抛出异常 * 使用内置的RAISEAPPLICATIONERROR过程抛出异常
6.3.1 RAISE语句
-
一、可以用于抛出一个在当前块自定义的异常,也可以抛出在STANDARD包中定义的系统异常。
RAISE exceptiojn_name;
-
二、需要一个包名做限定符
RAISE packagename.exceptionname;
-
三、不需要异常名称,但只可以用在异常处理单元的WHEN语句中。
EXCEPTION WHEN xxx THEN RAISE;
6.3.2 使用RAISE_APPLICATION_ERROR
使用RAISEAPPLICATIONERROR而不是RAISE的好处在于,你可以给异常加上一段错误消息。
PROCEDURE RAISE_APPLICATION_ERROR (
num binary_integer,
msg varchar2, --长度不能超过2K
keeperrorstack booleandefault FALSE);
6.4 处理异常
异常处理代码在程序中的位置是在所有可执行语句之后,在块的END语句之前。
DECLARE
... declarations ...
BEGIN
... executable statements ...
[ EXCEPTION
... exception handlers ...]
END;
WHEN exception_name [OR exception_name ...]
THEN
executable statements
WHEN OTHERS语句是可选 的,如果没有这个语句,任何未处理的异常立即传播到外层块。WHEN OTHERS 语句必须是异常处理部分的最后一个句柄。如果在WHEN OTHERS后面还有WHEN语句,会收到编译错误。
6.4.1 内置的错误函数
- SQLCODE返回代码块中最后一次抛出的错误代码,如果没有任何错误,返回0。ORACLE数据库用一个栈结构SQLCODE值。
- SQLERRM函数可以返回某个错误代码对应的错误消息。返回的字符串的最大长度是512个字节。
6.4.3 未处理异常
如果程序中抛出了一个异常,但这个异常并没有在当前的PL/SQL或者外层的块的异常处理单元被处理,这个异常就是未处理异常。PL/SQL会把这个未处理的异常作为错误一直返回到运行PL/SQL的应用环境。
6.4.4 传播未处理异常
抛出一个异常后,PL/SQL在当前块寻找针对该异常的处理句柄。如果没有发现匹配的句柄,PL/SQL会把异常传播到包含当前块的外层块中。PL/SQL通过在外层块再次抛出的方式尝试处理这个异常。这个动作会在后续的外层块中继续,直到没有能够抛出这个异常的块为止。当所有 的块都用尽了,PL/SQL就向执行最外层PL/SQL块的应用环境返回一个未处理异常。
如果你使用了局部定义异常,你就应该提供一个针对该错误名的异常句柄。
6.4.5 异常后继续
你可以通过给任何语句加上一个BEGINning,之后加上一个EXCEPTION单元和END语句构建一个“虚拟块”出来。用这种方法,你可以通过在代码中构建匿名块的方式来控制异常引起的失败范围。
6.4.6 WHEN OTHERS的处理代码
在异常处理单元里包含WHEN OTHERS语句,可以捕获所有其他的未处理异常。因为你没有明确指出对某些特殊异常的处理,你可能需要利用内置异常函数比如SQLCODE和DBMSUTILITY.FORMATERROR_STACK获得发生的错误的信息。