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
明晚继续努力,学习异常的高级概念。