子程序中的raise_application_error异常处理

时间:2014-11-17 15:31:49

标签: sql oracle exception plsql exception-handling

我有多个存储过程在我的数据库中调用多个存储过程。举一个小例子,我在下面构建了一些虚构的版本。在我的示例中,Java程序调用{​​{1}},调用calculate_bill,调用calculate_commission

我希望得到一些关于如何最好地将错误消息从堆栈传播到调用Java层的建议,以便用户获得与错误发生位置相对应的精确错误消息。

我真的很坚持这个。我在update_record的示例中玩过,并且不断地将它拖到堆栈中。我在下面的方式是远程正确吗?或者在相关程序中是否有一个raise_application_error,不需要raise_application_error等?

为了明白我的意思,在下面的例子中,如果用户输入的数字对应于由于不存在而无法更新的记录,我希望他们得到消息: “计算账单时出错。计算佣金时出错。没有记录需要更新”或其他相关内容。

所以有两个问题:

  1. 在应用程序层中为最终用户传递错误消息的最佳实践,最有效,最整洁的方法是什么?
  2. 有没有人对代码中更整洁的输出有任何建议,即连接这些错误以使它们更有意义的最佳方法?我非常愿意接受有关如何使这项工作做得最好的任何建议,因为我完全没有这方面的经验。
  3. 实施例: (代码错误):

    pragma exception init

    Java代码:

    -20000 : Error in top level procedure
    -20001 : Error in middle level procedure
    -20002 : Error in bottom level procedure
    

    Oracle代码:

    try {
        // call calculate_bill
    exception (SQLException ex)
        // output oracle code and relevant message.
    

    注意:我知道这个例子有点做作。我只是想保持简短。

1 个答案:

答案 0 :(得分:3)

我实现这个的方法是使用RAISE_APPLICATION_ERROR实际发生错误的地方,然后在其他层中保持未处理(或者,如果你想在数据库中登录,请在{{{ 1}}部分,然后使用OTHERS而不是RAISE重新加注。

RAISE_APPLICATION_ERROR个部分仍然存在上一个问题中出现的问题:当发生未知错误时,您将用一般的,无用的消息替换它。要解释Tom Kyte,“未在OTHERS中结束的WHEN OTHERS是一个错误。”

如果没有登录数据库,我会重新编写提供的代码,如下所示:

RAISE

下面是示例输入及其创建的堆栈跟踪:

create or replace procedure calculate_bill(in_num NUMBER) 
is
begin
    if in_num > 2 then
        calculate_commission(in_num);
else
    raise_application_error(-20000, 'Error calculating bill. ' || 'Record number doesn''t exist.', false);
end if;
end;

create or replace procedure calculate_commission(in_num NUMBER) 
is
begin
    if in_num < 30 then
        raise_application_error(-20001, 'Number too small to calculate commission.', false);
    elsif in_num >= 30 and in_num < 40 then
        update_record(in_num);
    else
        raise_application_error(-20001, 'Number too large to calculate commission', false);
    end if;
end;

create or replace procedure update_record(in_num NUMBER) 
is
v_stub number;
begin
  select 1 into v_stub from dual where 1 = 0;
exception
when no_data_found then
    raise_application_error(-20002, 'No record exists to be updated', false);
end;

如果您要将错误记录添加到这些过程,那么向exec calculate_bill(0) ORA-20000: Error calculating bill. Record number doesn't exist. ORA-06512: at "SCHEMANAME.CALCULATE_BILL", line 7 ORA-06512: at line 1 exec calculate_bill(10) ORA-20001: Number too small to calculate commission. ORA-06512: at "SCHEMANAME.CALCULATE_COMMISSION", line 5 ORA-06512: at "SCHEMANAME.CALCULATE_BILL", line 5 ORA-06512: at line 1 exec calculate_bill(35) ORA-20002: No record exists to be updated ORA-06512: at "SCHEMANAME.UPDATE_RECORD", line 8 ORA-06512: at "SCHEMANAME.CALCULATE_COMMISSION", line 7 ORA-06512: at "SCHEMANAME.CALCULATE_BILL", line 5 ORA-06512: at line 1 exec calculate_bill(100) ORA-20001: Number too large to calculate commission ORA-06512: at "SCHEMANAME.CALCULATE_COMMISSION", line 9 ORA-06512: at "SCHEMANAME.CALCULATE_BILL", line 5 ORA-06512: at line 1 部分添加OTHERS子句就很简单了:

EXCEPTION

WHEN OTHERS THEN my_logging (SQLCODE, SQLERRM, DBMS_UTILITY.format_error_backtrace ()); RAISE; 调用创建的新例外将由RAISE_APPLICATION_ERROR透明处理。