1

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

我的函数看起来像这样:

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
4

2 回答 2

2

您对异常的理解是正确的。然而,这是异常工作方式的一个值得注意的例外: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
于 2013-05-15T18:53:43.947 回答
1

异常会像您想象的那样工作并且“冒泡”,因此您必须在某个地方捕获它。

这就是正在发生的事情......你正在捕捉每一个异常,这不是最佳实践。如果您自己定义一个异常,您可以确保只捕获一个特定的异常。但是,这似乎不是您想要在这里做的。您只想重新引发一个异常

因此,您可以在单独的 package 中定义一个自定义异常,在您的子程序中引发它,然后在您的调用块中执行类似的操作:

begin
   RaiseException;

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

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

于 2013-05-15T15:56:01.420 回答