Sql 如何在Oracle软件包中记录所有异常?

Sql 如何在Oracle软件包中记录所有异常?,sql,oracle,oracle11g,Sql,Oracle,Oracle11g,我正在尝试将所有异常记录在Oracle包中。以下是我在程序结束时得到的信息: EXCEPTION WHEN OTHERS THEN INSERT INTO VSLogger (MESSAGE) VALUES ('Caught Exception'); 这很好,但是我还想记录错误代码和消息。我试过: EXCEPTION WHEN OTHERS THEN INSERT INTO VSLogger (MESSAGE) VALUES ('Caught Excepti

我正在尝试将所有异常记录在Oracle包中。以下是我在程序结束时得到的信息:

EXCEPTION
   WHEN OTHERS THEN
      INSERT INTO VSLogger (MESSAGE) VALUES ('Caught Exception');
这很好,但是我还想记录错误代码和消息。我试过:

EXCEPTION
   WHEN OTHERS THEN
      INSERT INTO VSLogger (MESSAGE) VALUES ('Caught Exception: Error ' || SQLCODE || ', Msg: ' || SQLERRM);
但这给了我一个错误:

490/7    PL/SQL: SQL Statement ignored
490/100  PL/SQL: ORA-00984: column not allowed here

正确的方法是什么?谢谢

不能直接使用
SQLERRM
——必须将其分配给中间变量。请注意,Oracle 9i会让您逍遥法外,但这一直都是问题所在。有关示例代码,请参见


您也可以考虑将该位包装在自治事务中,因此即使您的PL/SQL代码的事务被回滚,它也会被记录。

< P>盖乌斯给出了简短的答案。他关于将其包装成自治事务的评论非常重要。你会后悔你的交易被退回的那一天,你不知道为什么

这里展示了如何使用自治事务,并添加了一些额外的细节,这样您就可以更多地了解错误发生的位置

您的异常块如下所示:-

exception
   when exception_pkg.assertion_failure_exception then
      rollback;
      raise;
   when others then 
      rollback;
      v_code := SQLCODE;
      v_errm := SUBSTR(SQLERRM, 1, 255);
      exception_pkg.throw( exception_pkg.unhandled_except, v_code || ' - ' || v_errm || ' ($Header$)' );
。。。aaa并且,以下是支持此功能所需的所有代码。玩玩它,它很有用:-)


切勿使用
SQLERRM
SQLCODE
。不存储行号的异常日志记录是残酷的

始终使用
dbms_实用程序。格式化_错误|堆栈| dbms_实用程序。格式化_错误_回溯
,或类似的方法

例如,以下方框显示错误,但不显示错误发生的位置:

declare
    v_number number;
begin
    v_number := 1/0;
exception when others then
    dbms_output.put_line(sqlerrm);
end;
/

DBMS Output:
ORA-01476: divisor is equal to zero
此块显示错误及其发生的位置。这是对任何非平凡程序进行故障排除的关键信息

declare
    v_number number;
begin
    v_number := 1/0;
exception when others then
    dbms_output.put_line(dbms_utility.format_error_stack||dbms_utility.format_error_backtrace);
end;
/

DBMS Output:
ORA-01476: divisor is equal to zero
ORA-06512: at line 4

(以下是一些通用的异常处理建议。)

对于实际代码,您不希望简单地输出错误信息。事实上,最好的异常处理策略通常是什么都不做,并使用Oracle的默认行为来显示所有错误消息和行号

Oracle中的自定义异常处理通常仅适用于以下三种情况之一:

  • 您将对一个特定的错误执行某些操作,比如调用另一个忽略错误的过程
  • 如果这是一个仅用于数据库的程序,那么您可能希望在程序顶部(数量有限的)入口点捕获并记录异常。如果应用程序已经捕获了所有内容或内部代码,则不需要异常处理。异常会沿着堆栈向上传播,最好在最后捕获它们
  • 如果您需要记录某个仅作为局部变量存在的特定值,则必须立即记录该值,因为该值不会随异常传播

  • 有很多PL/SQL代码盲目地捕获并记录每个过程中的错误。这是不必要的,通常会适得其反。

    太棒了!明天我会把这件事搞砸的。到目前为止,我知道异常是“找不到数据”,但我不知道它来自何处,也不知道是什么引发的。这通常发生在嵌入式SQL语句对一组变量执行select操作时,而不是返回一行,而是不返回任何行。是的,尽管问题是它每天间歇性地发生大约10次,无缘无故!您使用相同的查询刷新页面,然后它再次工作。一个多星期以来,我们一直在努力寻找原因。使用上面的包,它将为您记录引发异常的代码行。这是它的优点之一。很高兴为您提供帮助,正如您从我的代码中的注释可以看出的那样,我从许多其他地方将其组合在一起,这是我的代码工作区中的标准之一:-)我无法正确安装该软件包。我得到了错误<代码> 115/12 PL/SQL:ORA-900942:表或视图不存在——但是,第115行在注释的中间,所以我不知道它在说什么。如果最好的策略是使用Oracle默认值,为什么会有例外?只是为了在某些场景中覆盖默认行为?你能提供一个用例吗?@Alexerm我在答案中添加了更多的信息。
    declare
        v_number number;
    begin
        v_number := 1/0;
    exception when others then
        dbms_output.put_line(dbms_utility.format_error_stack||dbms_utility.format_error_backtrace);
    end;
    /
    
    DBMS Output:
    ORA-01476: divisor is equal to zero
    ORA-06512: at line 4