【问题标题】:When to re-raise the same exception in Oracle何时在 Oracle 中重新引发相同的异常
【发布时间】:2016-01-15 08:09:32
【问题描述】:

我正在阅读 Steven Feuerstein 的 PL/SQL 书籍。根据它:

当你想重新加注(或传播出去)相同的东西时使用这种形式 异常处理程序中的异常,如您在此处看到的:

EXCEPTION 
 WHEN NO_DATA_FOUND 
 THEN 
 -- Use common package to record all the "context" information,
 -- such as error code, program name, etc. 
 errlog.putline (company_id_in); 
 -- And now propagate NO_DATA_FOUND unhandled to the enclosing block.
 RAISE; 

当您想要记录错误的事实时,此功能很有用 发生,但随后将相同的错误传递给封闭块。 这样,您可以记录应用程序中发生错误的位置,但 仍然停止封闭块而不会丢失错误 信息。

我试试看:

create table log_error
    ( 
      error_code number,
      error_name varchar2(400)
    );


 declare
    l_q number := 400;
    l_r number := 0;
    l_result number;
    err_num NUMBER;
    err_msg VARCHAR2(100);
begin
    l_result := l_q/l_r; 
 EXCEPTION
   WHEN OTHERS THEN
  err_num := SQLCODE;
  err_msg := SUBSTR(SQLERRM, 1, 100);
  insert into log_error values (err_num , err_msg);     
end;

select * from log_error;

我的 log_error 表中有以下数据:

-1476 ORA-01476: 除数等于零

现在我将raise 放在我的异常块中:

    declare
    l_q number := 400;
    l_r number := 0;
    l_result number;
    err_num NUMBER;
    err_msg VARCHAR2(100);
    begin
    l_result := l_q/l_r; 
    EXCEPTION
      WHEN OTHERS THEN
        err_num := SQLCODE;
        err_msg := SUBSTR(SQLERRM, 1, 100);
        insert into log_error values (err_num , err_msg);     
        raise;
   end;

现在当我运行这个块时,我的日志表中什么也没有,而且我也得到了错误。

Error report -
ORA-01476: divisor is equal to zero
ORA-06512: at line 14
01476. 00000 -  "divisor is equal to zero"

加薪有什么用?我什么时候必须使用这个?

【问题讨论】:

  • @LalitKumarB,原则上你是对的,但是我在这里假设 TO 尝试学习和理解一般的异常处理。

标签: oracle exception plsql


【解决方案1】:

您的日志记录过程需要有所不同。当调用异常时,所有未提交的数据/事务都将回滚。您可以使用 Oracle 添加的新功能添加更多详细信息。

err_msg := DBMS_UTILITY.FORMAT_ERROR_STACK()||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE(); 

您需要创建一个使用 PRAGMA AUTONOMOUS TRANSACTION 的日志记录过程。传入带有详细信息的 SQLCODE 和 err_msg,无论如何这都会记录错误。这是我使用的,它也使用了 Feurstein 的 Q Error 包。 Q$Error 包中的This link 提供了很多信息。

PROCEDURE LOG (err_in         IN INTEGER:= SQLCODE,
                  msg_in         IN VARCHAR2:= NULL,
                  vlocation_in   IN VARCHAR2:= NULL)
   IS
      /******************************************************************************
      PURPOSE: log a code error, business logic error or information message in APPLICATION_ERROR_LOGGING
      we want the error message to be logged even if the calling transaction fails or hangs
      ******************************************************************************/

      PRAGMA AUTONOMOUS_TRANSACTION;
      v_err_text   VARCHAR2 (4000) := SQLERRM;
   BEGIN
      v_err_text := v_err_text || ' ' || GET_MORE_ERROR_DESCRIPTION (err_in);

      INSERT INTO application_error_logging (ID,
                                                     request_uri,
                                                     ERROR_CODE,
                                                     user_id,
                                                     stack_trace,
                                                     information,
                                                     "TIMESTAMP")
        VALUES   (application_error_logging_seq.NEXTVAL,
                  vlocation_in,
                  TO_CHAR (err_in),
                  g_admin_id,
                  msg_in,
                  v_err_text,
                  localtimestamp);

      COMMIT;
   EXCEPTION
      WHEN OTHERS
      THEN
         q$error_manager.raise_error (
            error_code_in   => SQLCODE,
            text_in         => SQLERRM,
            name1_in        => 'LOCATION',
            value1_in       => 'APP_UTIL.LOG',
            name2_in        => 'v_location',
            value2_in       => vlocation_in,
            name3_in        => 'err_in',
            value3_in       => TO_CHAR (err_in)
         );
   END LOG;

【讨论】:

  • 这段代码很危险——没有记录错误的原始行号。 95% 的调试都是关于获取错误消息和行号。如果缺少其中任何一项,就会出现巨大的问题。
  • @JonHeller 我编辑了答案以包含 DBMS 回溯。
【解决方案2】:

显然,Steven Feuerstein 的过程errlog.putline() 使用自治事务将记录插入到日志表中。在您的情况下,您在同一事务中执行插入,当重新引发异常时,调用者会回滚。

【讨论】:

    猜你喜欢
    • 2014-07-09
    • 2011-01-29
    • 2020-07-14
    • 2021-10-04
    • 1970-01-01
    • 1970-01-01
    • 2021-09-17
    • 2010-11-07
    • 2012-07-16
    相关资源
    最近更新 更多