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

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

【问题讨论】:

    标签: oracle exception-handling plsql


    【解决方案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 或将错误作为文本传回。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-26
      • 2013-07-23
      • 1970-01-01
      相关资源
      最近更新 更多