【问题标题】:Function resumes execution after exception in subprogram子程序异常后函数恢复执行
【发布时间】:2013-05-10 05:32:37
【问题描述】:

我在子程序中引发了一个异常,我希望看到调用函数此时会暂停执行。但是,调用函数继续处理,就好像什么都没发生一样,我不明白为什么。

我的函数看起来像这样:

FUNCTION getFooCursor (i_blah IN VARCHAR)
    RETURN t_ref_cursor
IS
    v_sum_variable  NUMBER;
BEGIN
    --lookup number
    v_sum_variable := getNumber (i_blah);

    --call function that raises NO_DATA_FOUND exception
    doRaiseException();

    --the exception handler is only supposed to catch for this block
    BEGIN
        --do stuff and end up with a cursor
        RETURN barCursor(v_sum_variable);
    EXCEPTION
        WHEN OTHERS THEN
            --set some variables
    END
END;

假设doRaiseException() 看起来像这样:

PROCEDURE doRaiseException ()
IS
BEGIN
    RAISE NO_DATA_FOUND;
END;

当我在 TOAD 中调试此函数时,它会告诉我 NO_DATA_FOUND 异常已引发。但是,它会立即继续执行下一行(调用 barCursor() 的位置)并且函数结束,就好像没有出错一样。

出于测试目的,我曾尝试将doRaiseException(); 直接替换为RAISE NO_DATA_FOUND;(它实际上做的不止于此),这会在getFooCursor() 内停止执行,但无论SQL 再次调用它是否都会完全忽略该异常。

这就是异常在 PL/SQL 中的工作方式吗?他们不会像在 Java 或 C# 中那样冒泡吗?也许我错过了有关 Oracle 异常的一些重要信息。如何让异常冒泡到主机?


这是我的 Oracle 版本(从 v$version 返回):

Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi
PL/SQL Release 10.2.0.5.0 - Production                          
CORE    10.2.0.5.0  Production                                      
TNS for HPUX: Version 10.2.0.5.0 - Production                   
NLSRTL Version 10.2.0.5.0 - Production

【问题讨论】:

  • 你确定你的第一个函数看起来完全一样吗?异常会按照您的设想工作并“冒泡”,因此您一定在某个地方发现了它。
  • @Ben:我在我的示例中添加了一些信息,在阅读了您的评论后,这些信息突然显得更加相关。回想起来很明显......

标签: oracle exception plsql


【解决方案1】:

您对异常的理解是正确的。然而,这是异常工作方式的一个值得注意的例外:NO_DATA_FOUND 在 SQL 上下文中被静默忽略。这是一个“特性”,因为这是 Oracle 告诉其他进程没有更多数据要读取的方式。

对于自定义异常,您可能需要捕获 NO_DATA_FOUND 并将其作为不同的异常引发。这通常是一种处理异常的可怕方式,但这里没有好的选择。

SQL> create or replace function function1 return number is
  2  begin
  3     raise no_data_found;
  4     return 1;
  5  end;
  6  /

Function created.

SQL> select function1 from dual;

 FUNCTION1
----------


1 row selected.

SQL> create or replace function function2 return number is
  2  begin
  3     raise no_data_found;
  4     return 1;
  5     exception when no_data_found then
  6             raise_application_error(-20000, 'NO_DATA_FOUND raised');
  7  end;
  8  /

Function created.

SQL> select function2 from dual;
select function2 from dual
       *
ERROR at line 1:
ORA-20000: NO_DATA_FOUND raised
ORA-06512: at "JHELLER.FUNCTION2", line 6

【讨论】:

    【解决方案2】:

    异常会像你想象的那样工作并且“冒泡”,所以你一定在某个地方抓住了它。

    这就是正在发生的事情......您正在捕获每个异常,这不是最佳做法。如果您自己定义一个,您可以确保只有catch a specific exception。但是,这似乎不是您想要在这里做的。您只想重新引发单个异常。

    所以,你可以define a custom exception in a separate package,在你的子程序中提出它,然后在你的调用块中做这样的事情:

    begin
       RaiseException;
    
    exception
       when my_exception_package.my_exception then
          raise;
       when others then
          DoSomethingElse;
    end;
    

    这样您就可以捕获要引发的异常,然后重新引发它们。如果异常不同,则继续当前的程序流程。

    【讨论】:

      猜你喜欢
      • 2011-03-10
      • 2010-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-01
      • 2020-05-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多