当异常抛出后,控制无条件转到异常部分,这就意味着控制不能回到异常发生的位置,当异常被处理和解决后,控制返回到上一层执行部分的下一条语句。
BEGIN
DECLARE
bad_credit;
BEGIN
RAISE bad_credit;
--发生异常,控制转向;
EXCEPTION
WHEN bad_credit THEN
dbms_output.put_line('bad_credit');
END;
![]()
--bad_credit异常处理后,控制转到这里
EXCEPTION
WHEN OTHERS THEN
--控制不会从bad_credit异常转到这里
--因为bad_credit已被处理
END;
当异常发生时,在块的内部没有该异常处理器时,控制将转到或传播到上一层块的异常处理部分。
BEGIN
DECLARE ---内部块开始
bad_credit;
BEGIN
RAISE bad_credit;
--发生异常,控制转向;
EXCEPTION
WHEN ZERO_DIVIDE THEN --不能处理bad_credite异常
dbms_output.put_line('divide by zero error');
END --结束内部块
--控制不能到达这里,因为异常没有解决;
--异常部分
EXCEPTION
WHEN OTHERS THEN
--由于bad_credit没有解决,控制将转到这里
END;
异常传播
没有处理的异常将沿检测异常调用程序传播到外面,当异常被处理并解决或到达程序最外层传播停止。
在声明部分抛出的异常将控制转到上一层的异常部分。
BEGIN
executable statements
BEGIN
today DATE:='SYADATE'; --ERRROR
BEGIN --内部块开始
dbms_output.put_line('this line will not execute');
EXCEPTION
WHEN OTHERS THEN
--异常不会在这里处理
END;--内部块结束
![]()
EXCEPTION
WHEN OTHERS THEN
处理异常
END
执行部分抛出的异常将首先传递到同一块的异常部分,如果在同一块的异常部分没有处理这个异常的处理器,那么异常将会传播到上一层的异常部分中,一直到最外层。
在异常部分抛出的异常将控制转到上一层的异常部分。
处理异常将停止异常的传播和解决。有时用户希望在错误发生时,程序仍然能执行一些动作,要达到这个目的,可以把希望执行的动作放在异常处理器中,然后执行不带参数的RAISE语句,RAISE语句将重新抛出出现的异常,允许他继续传播。
DECLARE
order_too_old EXCEPTION;
BEGIN
RAISE order_too_old;
EXCEPTION
WHEN order_too_old THEN
DECLARE
file_handle UTL_FILE.FILE_TYPE;
BEGIN
--open file
file_handle:=UTL_FILE.FOPEN
(location=>'/ora01/app/oracle/admin/test/utlsir'
,filename=>'error.log'
.open_mode=>'W');
--write error stack
UTL_FILE.PUT_LINE(filehandle,
DBMS_UTILITY.FORMAT_ERROR_STACK);
--write the call stack
UTL_FILE.PUT_LINE(filehandle,
DBMS_UTILITY.FORMAT_CALL_STACK);
--close error log
UTL_FILE.FCLOSE(file_handle);
RAISE; --re-raise the exception
END
END
如果从FORMAT_XXX_STACK输出一个很大的值,那么使用DBMS_OUTPUT或UTL_FILE显示错误或调用堆的异常部分自身也会抛出异常,这两个堆常规下最多能返回2000字节,但utl_file.put_line被限制在1000字节以内,而dbms_output.put_line限制在512字节内。如果使用前面的代码并且不允许这种可能性,那么在异常处理器中将抛出一个未处理的异常。
GOTO语句不能用于将控制从执行部分传递到异常部分或反之。