Oracle:pl/sql 异常处理4

本文深入探讨了PL/SQL中的异常处理机制,包括异常的生成、捕获和处理流程,以及如何使用WHEN OTHERS处理未定义异常。此外,还介绍了如何利用PL/SQL提供的内建函数如SQLCODE、SQLERRM等进行异常诊断。
摘要由CSDN通过智能技术生成
异常处理
 
当异常生成之后,程序被中止,控制权交给异常处理模块,异常处理模块捕获当前异常句柄,并交由相应的程序处理;如果,异常促里模块没有捕捉到异常句柄,那么它将被传输到当前程序的外围。
 
除非由一些特殊的要求,一般情况下异常将再当前程序的异常处理模块中被处理。异常处理模块以 EXCEPTION 开始 END; 结尾。
       Declare
              /*…………*/
       begin
              /*…………*/
       exception
              when /* 异常名称 */
              then /* 异常处理 */
              when other
              then /* 异常处理 */
       end;
异常处理模块的语法基本上以 CASE 一致,凡是在 when 中有定义的异常都将被处理,而没有的则被传输。一个特殊的异常处理语句是 WHEN OTHERS 。就想在( 3 )中所说的,它会处理所有为被处理的异常,因此必须小心使用它,最好是在最外层的程序中。当然如果喜欢偷懒的,大可以在异常处理模块中只放一个 OTHERS 。注意,无论哪种情况, OTHERS 只能这只在异常处理的最后一位。
 
有趣的是,可以在一个 when 中处理多个异常句柄。
       Exception
              When no_data_found or invalid_employee_id or dbms_ldap.invalid session
              Then /*………..*/
       End;
       /
在这个例子里,有标准包的异常、自定义异常和非标准包中的异常。这些异常只能用 or 连接,不可以用 and ,因为只有一个异常能够生成。
 
非 raise_application_error 生成的异常,如果没有被处理而一直传递到系统环境中,那么环境将视情况作出相应的反映。在 sqlplus 中, oracle 将回滚所有 DML 对数据所做的修改。在 sqlplus 环境中,因为有自动回滚的存在,我们可以保留出现未被处理的异常的可能性;而在另外的一些环境中,则需要仔细设计最外层程序。
ü          捕捉任何有可能传出的异常。
ü          记录错误以便于分析。
ü          给外部环境一个信息,以便于其作出相应的处理。
 
对于自定义异常,因为 sqlcode 值永远是 1 ,所以当它被传出时,如果外围程序中没有定义相同名称的异常,我们将不知道是什么异常产生了。因此,不要将自定义异常传递出去。
 
在程序中处理几个互相独立的操作时,为了避免出现因为一个操作产生异常而使整个程序被中断的情况,有必要将这些独立的操作放在各自的虚拟块中。
       Procedure change_data is
       Begin
              Begin
                     Delete from employee where …..
              Exception
                     When others then null;
              End;
 
              Begin
                     Update company set …….
              Exception
When others then null;
              End;
 
              Begin
                     Insert into company_history select * from company where ….
              Exception
                     When others then null;
              End;
       End;
       /
 
 
Pl/sql 提供了一些内建的函数来帮助我们确定、分析异常。
 
SQLCODE
这个函数在前面有提到过,它是一个用于返回当前模块中最近一次异常值的函数,或者说是非入栈程序的异常值。打个比方:如果在当前程序的异常模块中调用了另一个程序, oracle 将当前程序及相应的环境变量(包括异常值)压入系统栈;在被调用程序中生成了一个值为 1 的异常,那么 sqlcode 将返回 1 ;之后刚才的程序出栈, sqlcode 返回当前异常值。需要注意的是,不要在异常模块之外使用它,这样不会有任何意义。当没有异常或在异常模块之外使用时, SQLCODE 返回 0 ;返回值 1 是指自定义异常。
 
SQLERRM
接收异常值,返回相应的长度不超过 512 字节的描述语。如果没有传入异常值,则返回当前异常描述。
       Begin
              Dbms_output.put_line( sqlerrm(-1403);
       End;
Sql>/
Ora-1403: no data found
在需要体构长度超过 512 字节的描述时, oracle 建议使用 dbms_utility.format_error_stack 。显然,用这个函数来判断一个异常是否为系统异常是很有用的,如果不是的话,将返回以下两种情况的一种。
如果是一个负数:
       ora-nnnnn: message not found,; product=rdbms; facility=ora
如果是一个正数:
       -nnnnn: non-oracle exception
 
DBMS_UTILITY.FORMAT_ERROR_STACK
返回当前异常相应的描述,没有字符长度限制。与 SQLCODE 相同的是,必须在异常处理模块中使用。虽然名称中有一个 stack 在,但通过它并不能知道异常的最初生成处,需要的话就必须使用 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE 。
 
DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
系统为最近一次生成的异常设置了一个栈,并跟踪它的传递过程,而这个函数使用这个栈,然后返回该异常的整个传递过程。这个函数对错误的定位和实施下一步处理起着至关重要的作用。
       Create or replace procedure procl is
       Begin
              Dbms_output.put_line(‘running proc1’);
              Raise no_data_found;
       End;
       /
       create or replace procedure proc2 is
       begin
              dbms_output.put_line(‘calling proc1’);
              proc1;
       end;
       /
       create or replace procedure proc3 is
       begin
              dbms_output.put_line(‘calling proc2’);
              proc2;
       exception
              when no_data_found
              then
                     dbms_output.put_line(‘error stack at top level’);
                     dbms_output.put_line(dbms_utility.format_error_backtrace);
       end;
       /
现在可以运行 proc3 来看看结果。
Sql>set serveroutput on;
Sql>begin
2                          dbms_output.put_line(‘proc3->proc2->proc1 backtrace’);
3                          proc3;
4      end;
5      /
    Proc3 -> Proc2 -> Proc1 backtrace
    calling proc2
    calling proc1
    running proc1
    Error stack at top level:
    ORA-06512: at "SCOTT.PROC1", line 4
    ORA-06512: at "SCOTT.PROC2", line 5
ORA-06512: at "SCOTT.PROC3", line 4
事实上,每次异常的产生都将重置这个异常栈,只是最后一次从系统栈出栈的是最外层的程序块,所以可以清楚地看到异常生成的整个过程。上面这个程序的执行过程是这样的:首先用 put_line 打印 Proc3 -> Proc2 -> Proc1 backtrace , 调用 proc3 ,当前程序入栈 => 打印 calling proc2 ,调用 proc2 , proc3 入栈 => 打印 calling proc1 ,调用 proc1 , proc2 入栈 => 打印 running proc1 ,生成 no_data_found 异常,该异常被压入异常栈中 => proc2 出栈,并检测到来自第 5 行调用传递过来的异常,将它在此压入异常栈 => proc3 出栈,并检测到来自第 4 行调用传递过来的异常,将它在此压入异常栈, dbms_utility.format_error_backtrace 将异常栈中信息反相打印出来 => 最外层程序出栈, end 。
以下是正确使用这个函数的一些注意事项:
ü          在当前程序的异常处理模块中调用这个函数。
ü          避免在中间程序中使用异常处理模块。
这样异常就能被正确地传输到最外层程序中,并打印出这个过程了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值