首页 > 解决方案 > 管理包中异常的最佳方法

问题描述

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

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

例如,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;

这是最好的方法吗?

问候, 马可

标签: oracleexceptionplsqlraise

解决方案


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

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

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

推荐阅读