pl/sql 中的错误处理

Posted

技术标签:

【中文标题】pl/sql 中的错误处理【英文标题】:Error handling in pl/sql 【发布时间】:2010-06-28 15:50:25 【问题描述】:

我想了解 PL/SQL 中的错误处理。谁能帮我找到有关此主题的简要说明?

【问题讨论】:

【参考方案1】:

每个块都可以有一个异常处理程序。示例:

DECLARE
    /* declare your variables */
BEGIN
    /*Here is your code */
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        /* HAndle an error that gets raised when a query returns nothing */
    WHEN TOO_MANY_ROWS THEN
        /* HAndle the situation when too much data is returned such as with a select-into */
    WHEN OTHERS THEN
        /* Handle everything else*/
END;

这个链接会告诉你更多:http://download.oracle.com/docs/cd/B13789_01/appdev.101/b10807/07_errs.htm

该链接将向您显示比我更详细的信息,以及有关如何创建自己的异常名称的示例。

总是让我感到困惑的一点是,如果你有一个函数并且你没有在异常处理程序中返回一个值,那么调用函数中就会抛出一个异常。没什么大不了的,但我似乎总是忘记那个。

【讨论】:

如果一个异常没有在较低的块中被捕获,它会被传播到更高的块(并最终传播到客户端)。旧规则适用 - 永远不要检查您不知道如何处理的错误情况。让它向上流动。更高级别的块将捕获它,或者调用将失败并且客户端应用程序(或用户)将处理它。【参考方案2】:

另一个答案中引用的 Oracle 文章非常值得一读。

需要添加一些额外的东西 - 捕获 PL/SQL 异常会丢失错误堆栈 - 即关于哪一行引发异常的确切信息。

这会使调试包含可能引发相同异常的多个位置的代码块变得困难(即,如果您有多个可能返回 NO_DATA_FOUND 的 SQL 语句)。这里的一种选择是将完整的错误堆栈记录为异常处理程序的一部分。

EXCEPTION
    WHEN TOO_MANY_ROWS THEN
         myLogger('Some useful information',DBMS_UTILITY.FORMAT_ERROR_STACK);
END;

如果您确实需要捕获异常,请将您的异常处理尽可能本地化到您想要捕获的位置,并且仅在万不得已时才使用 WHEN OTHERS。

您也可以“做某事并重新引发相同的异常”

EXCEPTION
     WHEN TOO_MANY_ROWS THEN
         closeSmtpConnection;
         RAISE;
END;

最有用的功能之一是命名和捕获 Oracle SQL 内部异常的能力。

DECLARE
   recompile_failed     EXCEPTION;
   PRAGMA EXCEPTION_INIT (recompile_failed,-24344);
BEGIN
   . . . . . .
EXCEPTION
   WHEN recompile_failed THEN 
      emailErrors(pObjectType,pObjectName);
END;

另一方面是能够引发用户定义的“SQL”异常

RAISE_APPLICATION_ERROR(-20001,'my text')

这是将用户定义的文本传播到调用应用程序的唯一方法,因为用户定义的 pl/sql 异常不会跨越“范围”边界。

不幸的是,尽管文档说 -20000 到 -20999 范围可用于用户定义的异常,但某些 Oracle 扩展包使用这些序列号,因此您不能仅依靠序列号来识别调用语言中的错误.

(大多数人倾向于将 RAISE_APPLICATION_ERROR 包装在其他代码中以记录错误,并且通常从表中导出错误文本)

我发现一个有用的技巧是在包体中创建一个包含“有状态”变量的包,以及简单的 setter 和 getter 函数。与数据库更新不同,包中的信息不会因错误而回滚。

在发生错误时,在包中设置信息,然后使用调用语言中的 getter 检索它,以构造“本机”异常。

至于用户定义的 pl/sql 异常 - 这些在本地代码中可能很有用,但在许多情况下,可以通过使用不同的控制结构来避免它们(即避免将它们用作替代 GOTO)。

在包头上创建全局异常,以指定包可能返回的可能异常似乎是个好主意,但最终结果是您的调用代码最终不得不处理可能在任何底层软件包。

我自己过去曾走这条路,现在我建议不要这样做 - 使包自包含并使用 RAISE_APPLICATION_ERROR 或将错误作为文本传回。

【讨论】:

以上是关于pl/sql 中的错误处理的主要内容,如果未能解决你的问题,请参考以下文章

检查 PL/SQL 异常块中的特定错误代码

PL/SQL 异常错误处理

在 DB2 PL/SQL 匿名块中声明局部变量和声明继续处理程序会导致错误?

ORACLE PL/SQL编程总结

PL/SQL 错误处理后继续执行

PL/SQL Oracle 错误处理