PL / SQL中多个特定异常的共享代码

时间:2019-06-26 14:09:49

标签: oracle plsql

我对PL / SQL还是很陌生,并且正在尝试为我编写的程序包实现一些异常处理。

我遇到了可能会引发多个异常的情况。

在引发这些异常的情况下,我可能想针对每个异常进行特定的操作,例如,如果引发异常A,则关闭并删除文件,但是如果引发异常B,则只需要关闭游标并发送电子邮件以警告某人发生致命错误。

这很好,我了解如何使用WHEN <EXCEPTION_NAME> THEN

我遇到的问题是,我无法编写针对任何异常而发生的通用代码,以在发生异常的情况下执行我一直希望做的事情,例如写入日志文件。这意味着我必须为每种异常类型复制代码行,如下所示。

DECLARE
    test_exception EXCEPTION;
BEGIN
    --some code
    RAISE test_exception;
    --some code
EXCEPTION        
    WHEN test_exception THEN        
        SEND_EMAIL('Something went wrong');
        WRITE_TO_LOG('Error ' || SQLCODE || ' | ' || SUBSTR(SQLERRM, 1, 200) || ' | ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
    WHEN OTHERS THEN     
        SOME_OTHER_FUNCTION();
        WRITE_TO_LOG('Error ' || SQLCODE || ' | ' || SUBSTR(SQLERRM, 1, 200) || ' | ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE); 
END;

我想要实现的是与此类似的东西,无法编译。

DECLARE
    test_exception EXCEPTION;
BEGIN
    --some code
    RAISE test_exception;
    --some code
EXCEPTION        

    WRITE_TO_LOG('Error ' || SQLCODE || ' | ' || SUBSTR(SQLERRM, 1, 200) || ' | ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);

    WHEN test_exception THEN        
        SEND_EMAIL('Something went wrong');
    WHEN OTHERS THEN      
        SOME_OTHER_FUNCTION();
END;

很显然,这个示例并不完整,但是给出了一个大概的想法。对于这样的一条重复的行来说,这不是问题,但是如果要关闭许多游标或文件或进行其他内务处理,这似乎有些冗长/乏味。

是否有WHEN ALL THEN子句或类似的子句?这是某种GOTO的用例吗?还是我在这里尝试应用错误的概念。

我似乎找不到有人问同样的问题,对我来说,这意味着我以错误的方式来解决这个问题,或者我缺少一些基本知识。

谢谢

2 个答案:

答案 0 :(得分:3)

PL / SQL将仅执行一个异常块。因此,如果您要针对每个异常运行一些通用代码(例如,日志记录),则必须在when others中执行。

然后检查sqlcode进行特定于异常的处理。例如:

begin

  raise TOO_MANY_ROWS;

exception
  when others then
    dbms_output.put_line ( 'Generic stuff' );
    case sqlcode 
      when -1422 then
        dbms_output.put_line ( 'TMR specific' );
      when -1476 then
        dbms_output.put_line ( 'ZD specific' );
      else
        null;
    end case;

    raise;
end;
/

Generic stuff
TMR specific

ORA-01422: exact fetch returns more than requested number of rows

begin

  raise ZERO_DIVIDE;

exception
  when others then
    dbms_output.put_line ( 'Generic stuff' );
    case sqlcode 
      when -1422 then
        dbms_output.put_line ( 'TMR specific' );
      when -1476 then
        dbms_output.put_line ( 'ZD specific' );
      else
        null;
    end case;

    raise;
end;
/

Generic stuff
ZD specific

ORA-01476: divisor is equal to zero

现在,这是否是一个的想法尚待商.。

when others异常块应以某种方式重新引发异常。这可以防止您抑制严重的意外错误(例如磁盘空间不足)。但是对于某些特定的例外情况,您可能需要进行处理。


附录

如果您有用户定义的异常,则需要通过魔杖来处理这些异常。一种方法是创建一个标准异常包。在其中,为将要使用的所有异常命名,初始化和定义值常量。

然后您可以将这些定义用于用户定义的异常:

create or replace package excepts as 

  user_defined exception ;
  user_defined_val pls_integer := -20001;
  pragma exception_init ( user_defined, -20001 );

end;
/

begin

  raise excepts.USER_DEFINED;

exception
  when others then
    dbms_output.put_line ( 'Generic stuff' );
    case sqlcode 
      when -1422 then
        dbms_output.put_line ( 'TMR specific' );
      when -1476 then
        dbms_output.put_line ( 'ZD specific' );
      when excepts.user_defined_val then
        dbms_output.put_line ( 'User-defined specific' );
      else
        null;
    end case;

    raise;
end;
/

Generic stuff
User-defined specific

ORA-20001: 

答案 1 :(得分:0)

如果我不能正确理解-解决方案非常简单。引发异常时,可以在嵌套块中处理它,并通过RAISE

传递给外部块
    DECLARE
    test_exception EXCEPTION;
begin
      RAISE test_exception;

    --some code
EXCEPTION        
    WHEN OTHERS THEN
      BEGIN
         dbms_output.put_line( 'WRITE_TO_LOG');
         RAISE;
      EXCEPTION
        WHEN test_exception THEN
          dbms_output.put_line( 'test_exception');
         WHEN OTHERS THEN
        dbms_output.put_line( 'some other function');
     end;
END;

输出:

WRITE_TO_LOG
send mail