oracle的exception学习、局部变量的学习

本文深入探讨了Oracle中触发异常的方式,包括自动触发、主动触发等,并详细介绍了如何使用raise、raise_application_error等关键字进行异常处理。文章还提供了实例代码,展示了异常传播和局部变量在异常处理过程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

oracle的触发异常方式和把握:

1 自动触发exception: 这种是被动的。

   设计expcetion,主要依赖于常见的分类,预期过程会报哪些错误,在异常处理部分就设计相应的报错返回信息,或者是处理。

2 主动触发:raise、raise_applition_error。

   raise触发的是,一个exception变量。如果要区分许多类的exception,就要定义许多不同名字的exception变量。这样不太合理。

   使用方面,从简约的角度考虑,定义几个exception变量,结合相应的稽核过程或者是稽核函数,根据返回的结果,raise相应对应的变量。

   这种应用,子过程处理问题的粒度相对较大,才会有意义。或者是一个exception代表的粒度较大,在处理部分,根据断点变量,用case或if语句处理相关数据。

 

   raise_applition_error的使用比较即兴,ora的值只要小于等于-20001就可以。后面定一个报错的信息。传入exception处理部分进行处理。

3 exception变量的捆绑,#prama exception_init,预期的被动,这个是将常见的分类中,将ora错误定义成一个exception变量。或者是为了处理特定的业务,或者程序bug、异常,定义一个ora的exception变量。

   当在处理业务的时候,被动触发了异常,在异常处理部分设计相应的报错返回信息,或者是处理数据。

   但是这个exception是过程变量,所以要封装在一个较小的过程里。或者是一个层次里的模块规模(代码量)不应该太大。

4 主动触发方式:

    exception 定义变量,用raise来主动触发。这个用法主要是根据业务稽核,判断业务不正确的时候的,raise exception_name。

    #pragma exception_init(ora_num, exception_name) 定义一个可预期的变量。如果跟raise_application_error结合使用,那么pragma的定义预期这个值。

    #pragma exception_init(ora_num, exception_name) 定义一个可预期的变量,使用被动触发,不调用raise的情况是,是一个预期的特殊处理。比如ora-04068(非普通)。

    被动触发:

    普通的处理,就是常见的ora异常。DML操作的异常。

 

例子:

declare
    a_b number;
    serv_a number;
begin
    a_b := 1;
    if a_b = 1 then
        dbms_output.put_line('1: ab = ' || a_b || ', 第一层');
    end if;
    begin
        a_b := 2;
        if a_b = 2 then
            dbms_output.put_line('2: ab = ' || a_b || ', 第二层');
        end if;
        select serv_id into serv_a from ls65_sid.serv_t a where rownum < 3;
        dbms_output.put_line('2: 第二层没有报错');    
    exception
        when others then
            dbms_output.put_line('2: 第二层报错了'||sqlerrm);
    end;
    case a_b
        when 1 then 
            dbms_output.put_line('1: 处理完第二层的程序,变量值还留在第一层, a_b = 1, 异常返回点在下一句,不在exception');
        when 2 then
            dbms_output.put_line('1: 处理完第二层的程序,变量值还留在第二层, a_b = 2, 异常返回点在下一句,不在exception');    
        else
            dbms_output.put_line('1: 例外了');
    end case;
    dbms_output.put_line('1: 第二层的异常返回后, 接下来是第一层的下一条语句, 并没有传入exception');    
exception
    when others then
        dbms_output.put_line('sqlerrm');        
end;

1: ab = 1, 第一层
2: ab = 2, 第二层
2: 第二层报错了ORA-01422: exact fetch returns more than requested number of rows
1: 处理完第二层的程序,变量值还留在第二层, a_b = 2, 异常返回点在下一句,不在exception
1: 第二层的异常返回后, 接下来是第一层的下一条语句, 并没有传入exception

这里检测的是异常的传播。进入了下一句,而非上一层的exception。

另外局部变量a_b的值,不像c++随着块的消失,值会改变。

这是因为oracle是c做的,c是汇编级语言做的,两者的层次不一样,设计的预期功能也是不一样的。

c是遇到块符号{会自动为这个变量开一个空间,遇到}会自动释放。但oracle就不是这么预期了。

 

raise_application_error注意:

1 raise_application_error(-20001, 'no')   问题。

begin
        a_b := 2;
        if a_b = 2 then
            dbms_output.put_line('2: ab = ' || a_b || ', 第二层');
        end if;
        raise_application_error(-20001, 'no')   
    exception
        when 'no' then
            dbms_output.put_line('2: 第二层报错了'||sqlerrm);
        when others then
            dbms_output.put_line('2: 第二层报错了'||sqlerrm);
    end;

 

这里的'no' 是错误的。exception的when检测是对exception变量来匹配名字的。

 

2  no exception 问题

declare
    a_b number;
    serv_a number;
    no exception;

begin
        a_b := 2;
        if a_b = 2 then
            dbms_output.put_line('2: ab = ' || a_b || ', 第二层');
        end if;
        raise_application_error(-20001, no);
    exception
        when no then
            dbms_output.put_line('2: 第二层报错了'||sqlerrm);
        when others then
            dbms_output.put_line('2: 第二层报错了'||sqlerrm);
    end;

 

这里有exception变量名也是不对的。因为raise_application_error本身就是异常。

 

3 应用:

由于raise_application_error比较灵活。它直接就是异常的输出部分。它本身有两个参数,一个是异常的ora编码,一个是编码的说明信息。

所以它在一个过程中应用时,总是会被异常抛出来。

使用方面特别适合触发器。

代码同一层:

触发器:定义DML操作时,当稽核业务不合理,或者相关的DML操作不正确时,直接中断操作。抛出异常,

                触发器将异常的ora编码传递给上一层的过程或者函数,进行exception操作。记录报错信息,或者是进行数据处理。

普通应用:调用exception,设置预期的ora编码,在exception进行相关处理。记录报错信息,或者是处理数据。(见下面例子)。

 

代码不在同一层:

               在上一层的代码中设置一个局部变量,将该变量通过in out传入该子过程或者函数、触发器,当在操作时触发了异常exception,就进行赋值。

               当out返回变量时,上一层的代码,就根据变量值,进行处理。注意:这里的代码处理方式,不是在exception,而是在调用子过程的下一条语句。(不写例子)

 

declare
    a_b number;
    serv_a number;
    no exception;
    pragma exception_init(no, -20001);
begin
    a_b := 1;
    if a_b = 1 then
        dbms_output.put_line('1: ab = ' || a_b || ', 第一层');
    end if;
    begin
        a_b := 2;
        if a_b = 2 then
            dbms_output.put_line('2: ab = ' || a_b || ', 第二层');
        end if;
        raise_application_error(-20001, '主动raise_application_error报错');
    exception
        when no then
            dbms_output.put_line('2: raise_application_error通过exception变量no,进行主动报错');
        when others then
            dbms_output.put_line('2: 第二层报错了'||sqlerrm);
    end;
    case a_b
        when 1 then 
            dbms_output.put_line('1: 处理完第二层的程序,变量值还留在第一层, a_b = 1, 异常返回点在下一句,不在exception');
        when 2 then
            dbms_output.put_line('1: 处理完第二层的程序,变量值还留在第二层, a_b = 2, 异常返回点在下一句,不在exception');    
        else
            dbms_output.put_line('1: 例外了');
    end case;
    dbms_output.put_line('1: 第二层的异常返回后, 接下来是第一层的下一条语句, 并没有传入exception');    
exception
    when no then
        dbms_output.put_line('1: 主动报错'); 
    when others then
        dbms_output.put_line(sqlerrm);        
end;

1: ab = 1, 第一层
2: ab = 2, 第二层
2: raise_application_error通过exception变量no,进行主动报错
1: 处理完第二层的程序,变量值还留在第二层, a_b = 2, 异常返回点在下一句,不在exception
1: 第二层的异常返回后, 接下来是第一层的下一条语句, 并没有传入exception

 

通过以上的练习,对exception就有了灵活的把握和应用了。好的代码,拥有好的结构和逻辑。

这个目标跟两个因素有关系: 1  业务  2  对exception设计思想的把握。

其中,业务比第二点还要重要。它是一个公司吃饭的本事,代码再好总得吃饭。

但是第二点练习好了,自己的能力上去了,到处吃饭都无所谓了。

 

现实是残忍的,公司的目标和个人的理想是不一致的。

在公司,它需要精益求精的技能,但成本上始终是个工具。员工想加薪水的理想,有点悲剧,所以受打击。

在个人,他需要精益求精的技能,为了能多点薪水,现实不能满足,也没办法总得提高竞争力。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值