Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oracle Pl/SQL嵌套过程异常处理_Oracle_Stored Procedures_Plsql_Exception Handling - Fatal编程技术网

Oracle Pl/SQL嵌套过程异常处理

Oracle Pl/SQL嵌套过程异常处理,oracle,stored-procedures,plsql,exception-handling,Oracle,Stored Procedures,Plsql,Exception Handling,这是一个关于通过多个级别的PL/SQL过程进行错误处理的最佳实践问题。我已经看了一些其他的问题来帮助我,特别是 目前,我有一个带有过程1的程序,它调用过程2,它调用过程3。我试图执行适当的错误处理,但我希望最终将确切的问题输出回应用层。我希望能得到一些关于如何有效和清晰地做到这一点的想法 我当前的解决方案方法如下所示,但对我来说似乎相当混乱,有很多变量声明。我对PL/SQL(以及一般的SQL)非常陌生,因此我非常感谢您对以下方面的建议: 处理多层过程时,良好的错误处理技术 将错误消息反馈到应用程

这是一个关于通过多个级别的PL/SQL过程进行错误处理的最佳实践问题。我已经看了一些其他的问题来帮助我,特别是

目前,我有一个带有过程1的程序,它调用过程2,它调用过程3。我试图执行适当的错误处理,但我希望最终将确切的问题输出回应用层。我希望能得到一些关于如何有效和清晰地做到这一点的想法

我当前的解决方案方法如下所示,但对我来说似乎相当混乱,有很多变量声明。我对PL/SQL(以及一般的SQL)非常陌生,因此我非常感谢您对以下方面的建议:

  • 处理多层过程时,良好的错误处理技术
  • 将错误消息反馈到应用程序层(在我下面的过程中,由“out\u totall\u output”变量表示)
  • 程序流程:UI->Proc 1->Proc 2->Proc 3

    程序1:

    --One input variable, one output.
    in_id                VARCHAR2;
    out_overall_output   VARCHAR2;
    ...
    DECLARE
        l_success         BOOLEAN;
        l_error_output    VARCHAR2(100);
    BEGIN
        Proc2(id, l_success, l_error_output);
        IF l_success = FALSE THEN
            out_overall_output = l_error_output
        END IF
    EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        out_overall_output:= 'Error calling Proc 2'
        RETURN;
    END;
    --Normal flow continues if l_success is true...
    
    --One input variable, two output.
    in_id                VARCHAR2;
    out_success          BOOLEAN;
    out_error_message    VARCHAR2;
    ...
    BEGIN
        DELETE 
        FROM table
        WHERE id = in_id;
    EXCEPTION
    WHEN NO_DATA_FOUND THEN
        out_success = FALSE;
        out_error_message = 'Error - No data to delete'
    WHEN OTHERS THEN
        out_success = FALSE;
        out_error_message = 'Error deleting data.'
    END;
    
    程序2:

    -- One input variable, two output.
    in_id
    out_success
    out_error_output
    //other logic
    DECLARE
        l_success         BOOLEAN;
        l_error_output    VARCHAR2(100)
    BEGIN
        Proc3(id, l_success, l_error_output)
        IF l_success = FALSE THEN
            out_error_output = l_error_output
        END IF
    EXCEPTION
    WHEN OTHERS
        out_error_output = 'Error calling Proc 3'
        RETURN;
    END;
    
    程序3:

    --One input variable, one output.
    in_id                VARCHAR2;
    out_overall_output   VARCHAR2;
    ...
    DECLARE
        l_success         BOOLEAN;
        l_error_output    VARCHAR2(100);
    BEGIN
        Proc2(id, l_success, l_error_output);
        IF l_success = FALSE THEN
            out_overall_output = l_error_output
        END IF
    EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        out_overall_output:= 'Error calling Proc 2'
        RETURN;
    END;
    --Normal flow continues if l_success is true...
    
    --One input variable, two output.
    in_id                VARCHAR2;
    out_success          BOOLEAN;
    out_error_message    VARCHAR2;
    ...
    BEGIN
        DELETE 
        FROM table
        WHERE id = in_id;
    EXCEPTION
    WHEN NO_DATA_FOUND THEN
        out_success = FALSE;
        out_error_message = 'Error - No data to delete'
    WHEN OTHERS THEN
        out_success = FALSE;
        out_error_message = 'Error deleting data.'
    END;
    

    注意:过程调用的级别比这更深。我所展示的代码片段大大简化了。我实际过程中的错误消息和变量名更具描述性。

    要展示应用程序级别“服务器发生了什么”的确切解释,可以尝试以下操作。在过程中:

    create or replace procedure p1 is
    ...
    exception
      when <some_error> then
        <do something>
        -- re-raise error:
        raise_application_error(-20001, 'Client with ID '|| ID || ' has no right to perform action "' || ACTION_NAME || '"', true);
    end;
    
    create or replace procedure p2 is
    begin
      p1;
    exception
      when <another_error> then
        <do something>
        -- re-raise error:
        raise_application_error(-20002, 'Action "' || ACTION_NAME || '" is not completed', true);
    end;
    
    create or replace procedure p3 is
    begin
      p2;
    exception
      when <another_error> then
        <do something>
        -- re-raise error:
        raise_application_error(-20003, 'Purchasing of "' || CAR_NAME || '" cancelled', true);
    end;
    
    程序
    raise\u application\u error
    with
    false
    值的第三个参数将删除所有以前的错误消息。如果在程序
    p3
    中使用false值,在本例中,您将只看到一条带有代码
    ORA-20003
    的错误消息

    另外,您还可以定义自己的异常,并在
    WHEN..THEN
    子句中使用它们。在这里您可以找到更多信息和示例:

    p.p.S.如何记录日志。日志过程:

    create or replace procedure top_level_procedure is
    begin
      p1;
    exception
      when <one_more_error> then
        <do something>
        raise_application_error(-20004, dbms_utility.format_error_backtrace);
    end;
    
    create or replace procedure log(p_log_message varchar2) is
    pragma autonomous_transaction;
    begin
      insert into log_table(..., log_message) values (..., p_log_message);
      commit;
    end;
    
      when <one_more_error> then
        <do something>
        log(..., dbms_utility.format_error_backtrace);
        raise_application_error(-20004, dbms_utility.format_error_backtrace);
    
    调用日志过程:

    create or replace procedure top_level_procedure is
    begin
      p1;
    exception
      when <one_more_error> then
        <do something>
        raise_application_error(-20004, dbms_utility.format_error_backtrace);
    end;
    
    create or replace procedure log(p_log_message varchar2) is
    pragma autonomous_transaction;
    begin
      insert into log_table(..., log_message) values (..., p_log_message);
      commit;
    end;
    
      when <one_more_error> then
        <do something>
        log(..., dbms_utility.format_error_backtrace);
        raise_application_error(-20004, dbms_utility.format_error_backtrace);
    
    什么时候 日志(…,dbms_实用程序。格式_错误_回溯); 引发应用程序错误(-20004,dbms实用程序。格式化错误\u回溯);
    通常,您应该避免通过参数传递错误,而是使用
    RAISE
    和/或
    RAISE\u APPLICATION\u ERROR
    在过程之间传递错误。在您的示例中,您会在错误发生时立即掩盖错误,这意味着当您遇到意外错误时,您不会知道真正的错误是什么。@Allan:你能给我解释得更详细一点吗?据我所知,如果我在过程3中遇到“when others”错误,我会跟踪并将其传递到链上。这不意味着我不知道真正的错误是什么吗?在上面的最后一个过程中,如果发生
    others
    错误,你总能得到消息“调用进程2时出错"。这是数字溢出错误吗?类型转换错误吗?分布式事务错误吗?可能有成千上万条错误消息。您通过将错误替换为通用消息来隐藏所有这些信息。出于好奇,您建议在何处登录您给出的示例?就在引发问题之前每次都会出现应用程序错误,或者在顶层的最后出现错误?如果答案是在顶层进行日志记录,那么如何记录整个raise_应用程序_错误片段?在本例中(以及大多数其他示例),我认为最好在顶层进行一次日志记录(一个事务而不是三个事务),但我不能说这是唯一可能的解决方案。我在post中添加了示例。
    dbms\u实用程序。format\u error\u backtrace
    是一个函数,在过程调用期间返回异常的“完整故事”。您可以将其值放入变量,然后执行所有您想要的操作。