Oracle异常 判断OTHERS处理程序中发生了哪个错误

9.4 判断OTHERS处理程序中发生了哪个错误

问题

你的代码因为一个异常而不断执行失败时,就会调用OTHERS处理程序。这时你需要做的就是准确地找出异常原因以便对它进行修复。

解决方案

像9.2节那样编写一个OTHERS异常处理程序,并利用SQLCODE和DBMS_UNILITY.FORMAT_ERROR_STACK函数返回Oracle的错误编码和抛出异常的消息内容。下面的例子演示了这两个函数的用法,还是使用9.3节中的过程,只是在调用OTHERS处理程序时增加了对错误代码和消息的处理。

CREATE OR replace PROCEDURE Salary_increase(emp_id       IN NUMBER, 
                                            pct_increase IN NUMBER) 
AS 
  salary       employees.salary%TYPE; 
  max_salary   jobs.max_salary%TYPE; 
  invalid_increase EXCEPTION; 
  error_number NUMBER; 
  error_message   VARCHAR2(1500); 
BEGIN 
  SELECT salary, 
         max_salary 
  INTO   salary, max_salary 
  FROM   employees, 
         jobs 
  WHERE  employee_id = emp_id 
         AND jobs.job_id = employees.employee_id; 

  IF ( salary + ( salary * pct_increase ) ) <= max_salary THEN 
    UPDATE employees 
    SET    salary = ( salary + ( salary * pct_increase ) ) 
    WHERE  employee_id = emp_id; 

    dbms_output.Put_line('SUCCESSFUL SALARY INCREASE FOR EMPLOYEE #: ' 
                         || emp_id 
                         || '.  NEW SALARY = ' 
                         || salary + ( salary * pct_increase )); 
  ELSE 
    RAISE invalid_increase; 
  END IF; 
EXCEPTION 
  WHEN no_data_found THEN 
    dbms_output.Put_line('UNSUCCESSFUL INCREASE, NO EMPLOYEE RECORD FOUND '
                     || 'FOR THE ' 
                     || 'GIVEN ID'); 
  WHEN invalid_increase THEN 
    dbms_output.Put_line('UNSUCCESSFUL INCREASE.  YOU CANNOT INCREASE THE ' 
                     || 'EMPLOYEE ' 
                     || 'SALARY BY ' 
                     || pct_increase 
                     || ' PERCENT...PLEASE ENTER ' 
                     || 'A SMALLER INCREASE AMOUNT TO TRY AGAIN'); 
WHEN OTHERS THEN 
           error_number := SQLCODE; 

           error_message := DBMS_UTILITY.FORMAT_ERROR_STACK; 

    dbms_output.Put_line('UNSUCCESSFUL INCREASE.  AN UNKNOWN ERROR HAS '
                     || 'OCCURRED, ' 
                     || 'PLEASE TRY AGAIN OR CONTACT ADMINISTRATOR' 
                     || ' Error #: ' 
                     || error_number 
                     || ' - ' 
                     || error_message);

END; 
/

过程执行时,如果有错误发生,就会出现下面的输出:

UNSUCCESSFUL INCREASE. AN UNKNOWN ERROR HAS OCCURRED, PLEASE TRY AGAIN OR CONTACT
ADMINISTRATOR Error #: -1722 - ORA-01722: invalid number

这个例子故意抛出一个错误,目的就是要演示这些工具函数的功能用法。如果能在异常发生时找到发生错误的代码行号那就再好不过了。如果编写能够返回错误行号的异常处理程序,请参考9.9节。

原理分析

SQLCODE和DBMS_UTILITY.FORMAT_ERROR_STACK函数提供了一种方法,可以找出引发终极异常抛出的代码和消息。函数SQLCODE会返回Oracle内部异常的错误编号,而+1则代表用户自定义异常,DBMS_UTILITY.FORMAT_ERROR_STACK函数会返回被抛出的Oracle内部异常消息,如果抛出的是用户定义异常,消息中则会包含User-Defined Exceptipn字样。用户自定义异常可以接受一个自定义的错误编号,具体信息可以参考9.9节。在这种情况下,函数SQLCODE会在异常抛出时返回自定义错误编号。
要使用这些函数,必须先把它们赋给一个变量,因为它们无法直接调用。比如你想在CASE语句中使用SQLCODE函数,就必须先把这个函数赋给一个变量。赋值完成后,就可以在语句中使用这个已经赋值的变量了。
Oracle中的DBMS_UTILITY.FORMAT_ERROR_STACK可以用来返回与当前错误相关联的错误消息。DBMS_UTILITY.FORMAT_ERROR_STACK最多可以保存1899个字符,所以,使用这个函数时,消息几乎不会被截断。SQLERRM是一个具有类似功能的函数,它也可以返回错误消息,但它最多只能显示512字节。所以使用SQLERRM时,消息经常会被截断。相比SQLERRM,Oracle更推荐使用DBMS_UTILITY.FORMAT_ERROR_STACK,因为这个工具函数不会把消息长度限制在这么小的范围内。
但是,SQLERRM也有它自己的重要位置,因为它可以为我们带来几个好处。SQLERRM一个很方便的特性就是你可以把一个错误消息编号传递给它,然后可以得到相应的错误消息。传入SQLERRM的任何错误编号都应该是负数,否则,你得到的消息就是一个用户自定义消息。表9-2列举了使用SQLCODE和SQLERRM时,它们分别对应的错误编号取值范围和消息。

这里写图片描述

如果你想选用SQLERRM,代码不会与使用DBMS_UTILITY.FORMAT_ERROR_STACK相差太多,但是可能需要增加一些代码截断结果。下面的例子演示的是用SQLERRM而不是DBMS_UTILITY.FORMAT_ERROR_STACK的过程实现。

CREATE OR replace PROCEDURE Salary_increase(emp_id       IN NUMBER, 
                                            pct_increase IN NUMBER) 
AS 
  salary       employees.salary%TYPE; 
  max_salary   jobs.max_salary%TYPE; 
  invalid_increase EXCEPTION; 
  error_number NUMBER; 
  error_message   VARCHAR2(150); 
BEGIN 
  SELECT salary, 
         max_salary 
  INTO   salary, max_salary 
  FROM   employees, 
         jobs 
  WHERE  employee_id = emp_id 
         AND jobs.job_id = employees.employee_id; 

  IF ( salary + ( salary * pct_increase ) ) <= max_salary THEN 
    UPDATE employees 
    SET    salary = ( salary + ( salary * pct_increase ) ) 
    WHERE  employee_id = emp_id; 

    dbms_output.Put_line('SUCCESSFUL SALARY INCREASE FOR EMPLOYEE #: ' 
                         || emp_id 
                         || '.  NEW SALARY = ' 
                         || salary + ( salary * pct_increase )); 
  ELSE 
    RAISE invalid_increase; 
  END IF; 
EXCEPTION 
  WHEN no_data_found THEN 
dbms_output.Put_line('UNSUCCESSFUL INCREASE, NO EMPLOYEE RECORD FOUND FOR THE ' 
                     || 'GIVEN ID'); 
  WHEN invalid_increase THEN 
dbms_output.Put_line('UNSUCCESSFUL INCREASE.  YOU CANNOT INCREASE THE EMPLOYEE ' 
                     || 'SALARY BY ' 
                     || pct_increase 
                     || ' PERCENT...PLEASE ENTER ' 
                     || 'A SMALLER INCREASE AMOUNT TO TRY AGAIN'); 
  WHEN OTHERS THEN 
           error_number := SQLCODE; 

           error_message := Substr(sqlerrm, 1, 150); 

dbms_output.Put_line('UNSUCCESSFUL INCREASE.  AN UNKNOWN ERROR HAS OCCURRED, ' 
                     || 'PLEASE TRY AGAIN OR CONTACT ADMINISTRATOR' 
                     || ' Error #: ' 
                     || error_number 
                     || ' - ' 
                     || error_message); 
END; 
/

除了上面介绍的几个工具之外,还有一些别的工具可以帮助我们诊断抛出的是哪些错误,甚至可以查看完整的栈跟踪。这些工具的用法将在9.9节进一步讨论。到那时,将9.9节和本节介绍的技术结合起来,就有更多的机会诊断程序的问题所在。

亚盘转换计算器app是一种用工具,能够帮助用户在亚盘和两种不同的盘口方式之间进行转换计算。在足球等体育比赛中,亚盘和是最常用的两种盘口方式,而它们的计算方式却存在一定的差异。因此,亚盘转换计算器app的出现,解决了用户在不同盘口方式之间进行计算的难题。 该app使用简单方便,用户只需在输入框中填入相应的亚盘或数据,app即可根据用户输入的数据进行转换计算,并给出相应的结果。用户可以通过该app将亚盘率转换为率,或将率转换为亚盘率,从而更好地理解比赛的胜负走势和下注的可能性。 亚盘率和率的转换计算涉及到一定的数学公式和算法,而亚盘转换计算器app将这些计算过程进行了程序化处理,提供了快速、准确的计算结果。这为用户节省了大量的时间和精力,使得他们能够更加专注于分析比赛和制定策略。 该app具有用户友好的界面设计和操作方式,使得用户能够快速上手并使用它进行转换计算。同时,该app也具有良好的数据更新和稳定性,确保用户能够随时随地获取到最新的亚盘和数据,并进行转换计算。 总之,亚盘转换计算器app是一款功能强大、用便捷的工具,能够帮助用户在亚盘和两种盘口方式之间进行转换计算,为他们提供更好的比赛分析和下注决策参考。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值