【问题标题】:OTHERS exception does not catch errorsOTHERS 异常不捕获错误
【发布时间】:2020-11-17 17:38:09
【问题描述】:

当我运行程序时,它会抛出以下错误(第一个是正确的):

BEGIN SP_REGI_OFIC('AD_PRO','Profesor',2000,'Hola'); END;
Error report -
ORA-06502: PL/SQL: numeric or value error: character to number conversion error

'OTHERS'你不应该发现这个错误吗?

CREATE OR REPLACE PROCEDURE SP_REGI_OFIC
(codigo_jobs IN jobs.job_id%TYPE,
titulo_jobs IN jobs.job_title%TYPE,
min_salario  IN jobs.min_salary%TYPE,
max_salario IN jobs.max_salary%TYPE)
AS
   
BEGIN

INSERT INTO JOBS(job_id, job_title, min_salary, max_salary)
VALUES (codigo_jobs,titulo_jobs,min_salario,max_salario);
COMMIT;
Dbms_output.put_line('Empleado creado con éxito');

EXCEPTION  
    WHEN DUP_VAL_ON_INDEX THEN
        dbms_output.put_line('Ya existe un oficio con el código ingresado');
    WHEN OTHERS THEN 
        dbms_output.put_line('Error:'||TO_CHAR(SQLCODE));
        dbms_output.put_line('Ha ocurrido un error:' ||SUBSTR(SQLERRM, 1,110));  
END SP_REGI_OFIC;
   
EXECUTE SP_REGI_OFIC('AD_PRES','President',20080,40000);
EXECUTE SP_REGI_OFIC('AD_PRO','Profesor',2000,'Hello');

【问题讨论】:

  • 错误是在绑定/分配实际值到参数期间。 max_salario IN jobs.max_salary%TYPE = 'Hola' 此时存储过程甚至还没有开始它的开始块
  • 这个错误可控吗?
  • 您可能希望将参数声明为 VARCHAR2,然后在将它们转换为用于插入的数字之前在内部对其进行验证。

标签: oracle plsql


【解决方案1】:

首先,您不应该使用when others then,尤其是当您仅使用它来将一些有限的细节放入dbms_output 缓冲区时。您的应用程序不会读取此缓冲区,您不会发现错误。当 SQL 知道语句出错时,这也会影响您获得的事务处理 - 您最终会得到逻辑上损坏的数据。

也就是说,直接回答您的问题: 异常块只会捕获从该过程范围内(beginexception 语句之间)抛出的异常。

捕获此运行时错误的明显方法是在发生执行错误的范围内使用异常块。

BEGIN 
  SP_REGI_OFIC('AD_PRO','Profesor',2000,'Hola'); 
exception when others then
  dbms_output.put_line('Errors shmerrors');
END;
/

但这非常值得付出努力 - 调用者是否应该知道有错误?是否需要在某处记录?交易需要清理吗?如果您不确定,那么通常最好的答案是将其留给 Oracle 将错误抛出给调用者的默认行为。

【讨论】:

    【解决方案2】:

    PL/SQL 中的异常处理程序只能捕获运行时错误。您得到的错误是编译错误。据推测,jobs.max_salary%TYPE 是一种数字数据类型,但您传递的字符串不能转换为数字。

    几乎总是可以将编译错误转换为运行时错误。在这种情况下,您可以将所有输入参数定义为字符串,并尝试在内部将它们转换为正确的数据类型,然后再在查询中使用它们。但请注意,将编译错误转换为运行时错误几乎总是错误的。在部署代码之前,编译错误相对容易彻底检测和解决。运行时错误通常取决于输入参数,因此很难彻底检测到。当返工代码成本更高时,运行时错误也往往会在开发过程的后期被检测到。通常,您最好立即被编译器告知您正在错误地调用一个方法,而不是您已经开发了一堆代码,将其部署到测试环境,然后 QA 人员回来了运行时错误告诉您将错误类型的参数传递给某些 API,您必须调试这是如何发生的。

    【讨论】:

    • 通过@JustinCave添加cmets,不仅运行时错误更难找到,使用WHEN OTHERS(恕我直言)几乎总是一个BUG,除非它后面跟着RAISE,尤其是因为dbms_output实际上是非- 存在 QA 或 Prod 环境。它的作用是告诉 Oracle 绕过报告错误,因此您的用户永远不会得到错误的指示,但是用户操作没有成功完成。如果您认为在运行时查找错误很困难,请在一周后尝试在某些操作失败时找到它,因为这取决于您刚刚忽略的内容。
    猜你喜欢
    • 2015-06-11
    • 2014-03-21
    • 2010-12-14
    • 2017-07-05
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    • 1970-01-01
    • 2018-03-23
    相关资源
    最近更新 更多