【问题标题】:Best way to manage exception in package管理包中异常的最佳方法
【发布时间】:2021-08-17 22:59:48
【问题描述】:

我有一个包含多个过程和函数的包,这些过程是从外部程序调用的,然后它们又调用函数。

管理异常的最佳方式在哪里?

例如,Prog1 调用 Proc1,Proc1 调用 Funct1,如果在函数中出现异常(“TOO MANY ROW”或“NO DATA FOUND”),这是引发特定自定义消息并立即返回的最佳方式到 Prog1。

在这一刻我有这个

PROCEDURE_1
BEGIN
   *code*
   CALL FUNCTION_1
   *code*
EXCEPTION
   WHEN NO DATA FOUND THEN
      *print customized message*
      RETURN;
END;

   
FUNCTION_1
BEGIN
   *code*
EXCEPTION
   WHEN NO DATA FOUND THEN
     RAISE;
END;

这是最好的方法吗?

问候, 马可

【问题讨论】:

  • when no data found then raise; 没有任何意义,因为无论如何它都会这样做。在函数中完全没有异常处理会更干净。在程序中,您希望“打印自定义消息” 做什么?如果你想让调用者知道它失败了,那需要是一个使用raise_application_error的实际异常。
  • 我需要创建 JSON 格式的自定义消息。我尝试使用 raise_application_error 但消息未打印在输出中
  • "没有找到数据然后引发是没有意义的;因为无论如何它都会这样做。"是的,没关系,但如果异常在函数中,程序会一直持续到结束,而我需要程序结束任何错误。
  • 调用者能否检测到程序失败,并通过将错误消息替换为JSON格式的客户消息来处理异常?或者,让过程通过 OUT 参数传回状态,但过程总是报告成功完成,调用者必须检查消息文本以了解它是否真的成功。
  • 我不确定您所说的是什么意思,但如果异常在函数中,则该过程将一直持续到最后,而我需要为任何错误结束该过程。如果函数因未处理的异常而失败,则该过程将在此处失败。

标签: oracle exception plsql raise


【解决方案1】:

理想情况下,如果出现完全错误,则允许过程因异常和错误堆栈而失败,但是致命错误和预期条件之间的差异将根据您正在实施的业务逻辑而有所不同,因此很难说出在您的特定情况下应该发生的事情。

如果约定的接口是程序应返回格式化消息,并且该消息可能包含预期的业务条件,例如产品缺货,那么您可以在程序中使用类似这样的东西来处理它(废话伪代码仅说明方法):

create or replace procedure procedure_1
    ( p_result_message out varchar2 )
as
    somevar number;
begin
    do_stuff('fruit','cake');
    
    begin
        somevar := function_1('bananas');
    exception
        when no_data_found then
            p_result_message := 'No kittens are available for this mission.';
            return;
    end;

    p_result_message := 'Cake is available in aisle 3';
exception 
    when something_else then
        p_result_message := 'Self-destruct sequence initiated.';
end;

(对于更纯粹的方法,您可能更喜欢重新排列代码,使其始终以 p_result_message 的值到达末尾,而不是在出现某些情况时中途退出。)

现在您可以处理function_1 中可能合理出现的任何异常,而无需在函数本身内进行任何特殊处理。

您也可以让函数引发包中定义的异常,尽管这样您就失去了在故障点定义诊断错误消息的能力,而且根据我的经验,这只会使事情复杂化。但为了说明:

create or replace package starfleet
as
    shield_failure exception;
    warp_core_malfunction exception;

    pragma exception_init(shield_failure, -20998);
    pragma exception_init(warp_core_malfunction, -20999);

    procedure check_status
        ( status_message out varchar2 );

    function status
        return number;

end starfleet;
create or replace package body starfleet as

    function status
        return number
    is
        status_ind number;
    begin
        select 1 into status_ind from dual where 1=2;  -- fails with NDF
        return status_ind;
    exception
        when no_data_found then raise shield_failure;
    end status;

    procedure check_status
        ( status_message out varchar2 )
    is
        status_ind number;
    begin
        status_ind := status();
        status_message := 'Everything is fine';
    exception
        when warp_core_malfunction then status_message := 'Abandon ship';
        when shield_failure then status_message := 'Increase power to shields';
    end check_status;

end starfleet;

现在,status() 函数可以引发包(或任何其他包)中定义的异常,并且过程check_status 可以捕获它并决定如何处理它。

从 SQL*Plus 调用它的示例:

SQL> var status_message varchar2(100)
SQL>
SQL> begin
  2      starfleet.check_status(:status_message);
  3  end;
  4  /

PL/SQL procedure successfully completed.


STATUS_MESSAGE
-------------------------
Increase power to shields

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多