PL/SQL 异常的传播

今晚看了关于PL/SQL异常传播的内容,做个笔记。

1.PL/SQL执行语句块发生运行时错误

PL/SQL 语句块的可执行部分发生某个运行时错误,执行权会转到该语句块的异常处理部分。当与该异常相关的语句执行完毕之后,执行权会转到主机环境或者外围语句块。如果不存在该错误的异常处理程序,该异常就会被传播到外围语句块,然后再次执行刚才所描述的步骤。如果没有发现异常处理程序,则程序执行会终止,执行权会转到主机环境。请看下例:

 1 begin
 2   declare
 3     a number := 4;
 4     b number := 0;
 5   begin
 6     a := a/b;
 7     dbms_output.put_line('a is ' || a);
 8   exception 
 9     when zero_divide then dbms_output.put_line('inner zero divide');
10   end;
11   dbms_output.put_line('can u see me?');
12 end;

执行之后在第6行抛出一个异常,执行权转到exception,在里面被捕获,并执行相应语句,此后执行权转到外围语句块。因此第7行不会执行,转而执行第11行。

所以输出结果是:

1 inner zero divide
2 can u see me?

但如果在内部的异常处理块无法与之匹配捕获,那么异常将传播到外围语句块的异常处理部分进行处理,来看下面的例子:

 1 begin
 2   declare
 3     a number := 4;
 4     b number := 0;
 5   begin
 6     a := a/b;
 7     dbms_output.put_line('a is ' || a);
 8   exception 
 9     when value_error then dbms_output.put_line('inner value error');
10   end;
11   dbms_output.put_line('can u see me?');
12 exception
13   when zero_divide then dbms_output.put_line('outter zero divide');
14 end;

在第6行抛出异常后,执行权转换到异常处理块,同样第7行不会执行。在内部异常处理块,该异常不是value_error,那么异常将传播到外围语句块的异常处理部分,因此第11行不会执行,在第13行捕获异常,输出语句。

1 outter zero divide

如果异常在内部就捕获了,即使内部异常处理的类型与外部异常处理的类型一样,也不会传播到外部,因为已经在内部处理了。因此将上面第9行的value_error改为与外面一样的zero_divide,第13行照样执行。

2.PL/SQL语句块声明部分发生运行时错误

PL/SQL语句块声明部分发生运行时错误,如果没有外围语句块,执行权将转换到主机环境(即报错),而不会转到该块的异常处理部分。那么要捕获该异常,只需要在外部加上语句块即可。

 1 begin
 2   declare
 3        a char(2) := 'hello';
 4   begin
 5        dbms_output.put_line('a is ' || a);
 6   exception
 7        when invalid_number or value_error then dbms_output.put_line('inner error');
 8   end;
 9   dbms_output.put_line('hello world');
10 exception
11   when invalid_number or value_error then dbms_output.put_line('outter error');
12 end;

如上面代码,在声明部分抛出异常,接下来异常被传播到第10行的外部异常处理部分,因此第5和第9行都不会执行,第11行被执行,输出如下。

1 outter error

3.再次抛出异常

在有些情况下,也许希望当发生特定类型的错误时,能够停止当前程序。也就是说,在内部抛出异常后,如果在内部处理完那么外部语句将继续执行,如果想一出现异常就停止程序,那么可以将异常传递到外部语句块,让外部语句块的异常处理部分进行处理,这个过程叫再次抛出异常。关键在于内部捕获到异常后,使用raise关键字将其传播出去。

 1 begin
 2   declare
 3        a char(2);
 4   begin
 5        a := 'hello';
 6        dbms_output.put_line('a is ' || a);
 7   exception
 8        when invalid_number or value_error then raise;
 9   end;
10   dbms_output.put_line('hello world');
11 exception
12   when invalid_number or value_error then dbms_output.put_line('outter error');
13 end;

如上面代码,第8行捕获到异常后,将其再次抛出,被外部程序所捕获,因此外部的第10行不会被执行,结果如下:

1 outter error

明晚继续努力,学习异常的高级概念。

 

原文地址:https://www.cnblogs.com/kingsleylam/p/3025379.html