首页 > 数据库 >PLSQL的异常传播

PLSQL的异常传播

时间:2023-09-18 16:23:29浏览次数:31  
标签:notice end PLSQL -- 捕获 传播 异常 raise

文章概要:

本文对主要就PLSQL的异常传播进行知识性小结,分为四个部分,PLSQL异常传播小结,编写小案例验证5种传播规则,示例了一个容易理解出错的案例,以及使用goto结合异常处理的案例。

一,异常传播规则

PLSQL块结构,典型如下:

declare
   --声明区域
begin
   --执行区域
exception
   --异常处理区域
end

上述三个区域都可以产生异常(PLSQL自动抛出来的,或者代码主动抛出来的异常),PL/SQL采用统一异常处理机制,当异常发生时,程序会自动跳转到异常处理区域,交给异常处理程序进行异常匹配,
处理完异常后,程序的控制流程继续向外部传递。
就传播规则而言,分两大情况,5小情况。

1,执行区域产生异常时,异常传播方式分为下三种情况:
1)如果当前语句块有该异常的处理器,则程序流程转移到该异常处理器,并进行异常处理。然后,程序的控制流程传递到外层语句块,继续执行。
2)如果当前语句块没有该异常处理器,则在外层语句块的异常处理部分处理该异常。处理完异常后,程序的控制流程继续向外部传递。
3)如果当前语句块及其外层语句块都没有对该异常的处理,则该异常将传播到调用环境(比如ksql客户端)或主机环境。
简而言之,异常会向他的当前子块传播,不能被捕获,则向外层进行传递,

2,声明区域和异常处理区域产生的异常传播策略有明显不同:
会立刻传播到外层语句块的异常处理部分, 即使当前语句块有该异常的异常处理器也不会进行捕获处理。
4)如果外层语句块无法处理该异常,则异常继续向更外层传播,直到调用环境或主机环境。
5)当外层语句块捕获并处理内层块的异常后,程序流程继续 向外层传递并执行。
任何情况(指1-5五种情况),直到异常被捕获则终止或最终到调用环境或主机环境。

二,异常传播实例

用尽可能简单的例子对上述5个情况进行实测:
1)如果当前语句块有该异常的处理器,则程序流程转移到该异常处理器,并进行异常处理。然后,程序的控制流程传递到外层语句块,继续执行。
--1

begin
   select 1/0 as result;
exception
   when others then
      raise notice '当前块捕获到异常';
end;
--运行结果
NOTICE:  当前块捕获到异常
ANONYMOUS BLOCK

--2

begin
   begin
      select 1/0 as result;
   exception
      when others then
        raise notice '内块捕获到异常';
   end;
   raise notice '继续执行程序';
exception
   when others then
      raise notice '外块捕获到异常';
end;
--运行结果
NOTICE:  内块捕获到异常
NOTICE:  继续执行程序
ANONYMOUS BLOCK

2)如果当前语句块没有该异常处理器,则在外层语句块的异常处理部分处理该异常。处理完异常后,程序的控制流程继续向外部传递。

begin
    begin
       begin
          select 1/0 as result;
       --exception        -- 注释掉异常处理块
       --   when others then
       --       raise notice '内块捕获到异常';
       end;
    exception
       when others then
          raise notice '外块捕获到异常';
    end;
    raise notice '继续执行程序';
end;    
--运行结构
NOTICE:  外块捕获到异常
NOTICE:  继续执行程序
ANONYMOUS BLOCK

3)如果当前语句块及其外层语句块都没有对该异常的处理,则该异常将传播到调用环境(比如ksql客户端)或主机环境。

begin
   select 1/0 as result;
end;
--运行结果
ERROR:  division by zero
CONTEXT:  SQL statement "select 1/0 as result"
PL/SQL function inline_code_block line 2 at SQL statement

**4)如果外层语句块无法处理该异常,则异常继续向更外层传播,直到调用环境或主机环境。 **
--1

declare
    vv CONSTANT NUMBER(2):=500; ---在本地声明部声明常量,numeric field overflow
begin
    raise notice '变量vv值为:%',vv;
exception
   when others then
      raise notice '最外层块捕获到异常';
end;
--运行结果
ERROR:  numeric field overflow
DETAIL:  A field with precision 2, scale 0 must round to an absolute value less than 10^2.
CONTEXT:  PL/SQL function inline_code_block line 3 during statement block local variable initialization

--2

declare
    declare
        vv CONSTANT NUMBER(2):=500; ---在本地声明部声明常量,numeric field overflow
    begin
        raise notice '变量vv值为:%',vv;
    exception
        when others then
          raise notice '声明区域捕获到异常';
    end;
begin
    raise notice '继续执行程序';
exception
   when others then
      raise notice '外层块捕获到异常';
end;
--运行结果
ERROR:  numeric field overflow
DETAIL:  A field with precision 2, scale 0 must round to an absolute value less than 10^2.
CONTEXT:  PL/SQL function inline_code_block line 4 during statement block local variable initialization

--3

begin
    declare
        vv CONSTANT NUMBER(2):=500; ---在本地声明部声明常量,numeric field overflow
    begin
        raise notice '变量vv值为:%',vv;
    exception
        when others then
          raise notice '声明区域捕获到异常';
    end;
    raise notice '继续执行程序';
exception
   when others then
      raise notice '外层块捕获到异常';
end;
--运行结果:
NOTICE:  外层块捕获到异常
ANONYMOUS BLOCK

5)当外层语句块捕获并处理内层块的异常后,程序流程继续向外层传递并执行。

begin
    begin
        declare
            vv CONSTANT NUMBER(2):=500; ---在本地声明部声明常量,numeric field overflow
        begin
            raise notice '变量vv值为:%',vv;
        exception
            when others then
              raise notice '声明区域捕获到异常';
        end;
        raise notice '继续执行程序1';
    exception
       when others then
          raise notice '外层块捕获到异常';
    end;
    raise notice '继续执行程序2';
end;
--运行结果
NOTICE:  外层块捕获到异常
NOTICE:  继续执行程序2
ANONYMOUS BLOCK

三,一个易理解错误的例子

再来看一个容易理解出错的案例:

declare
   --声明区域
   function func_test ()  return int
   as
   declare
      a int;
   begin
       a = 10;
       select a/0;
       return 1;
   exception
       when others then
          raise notice '函数内捕获到异常';
   end;
begin
    raise notice '测试';
    select func_test();
exception
    when others then
          raise notice '块外捕获到异常';
end
--运行结果:
NOTICE:  测试
NOTICE:  函数内捕获到异常
NOTICE:  块外捕获到异常

 func_test
-----------

(0 rows)

这个案例在函数内和快外都捕捉到了异常,难道异常传播了两次?实际不是,看下面这个例子一目了然

declare
   --声明区域
   function func_test ()  return int
   as
   declare
      a int;
   begin
       a = 10;
       select a/0;
       return 1;
   exception
       when zero_divide  then
          raise notice '函数内捕获到异常--》%',sqlerrm;
   end;
begin
    raise notice '测试';
    select func_test();
exception
    when others then
          raise notice '块外捕获到异常--》%',sqlerrm;
end
--运行结果
NOTICE:  测试
NOTICE:  函数内捕获到异常--》division by zero
NOTICE:  块外捕获到异常--》control reached end of function without RETURN

 func_test
-----------

(0 rows)

到此实际上已经真相大白,是因为嵌套函数func_test的exception没有返回值造成。
这个例子从侧面说明了,不管何时,尽量通过异常名称捕获异常,针对特定的错误进行处理,尽量少使用OTHERS异常处理器。
但在最外层块的异常处理部分放置OTHERS异常处理器,避免有未被处理的异常,是没有问题的。

四,GOTO结合异常处理

如前文所说PL/SQL采用统一异常处理机制,当异常发生时,程序会自动跳转到异常处理区域,交给异常处理程序进行异常匹配,
处理完异常后,程序的控制流程继续向外部传递顺序执行下去。
如果在处理完异常后,修复了异常后,我们不希望异常向外部传递后顺序执行下去呢?我们可以用GOTO进行跳转。
GOTO语句不能跳转到异常控制程序。同样,GOTO语句也不能从异常控制程序跳转到当前块。
例如,下面的GOTO语句就是非法的:

declare
    a int;
begin
    a = 0;
    <<zero_divide_label>>
    a = 10/a;
    raise notice '测试结果:%',a;
exception
    when zero_divide then
          raise notice '块外捕获到异常--》%',sqlerrm;
          a = 1;
          GOTO zero_divide_label;   ----非法的跳转到当前块
end
--运行结果
ERROR:  illegal GOTO statement, cannot transfer control to label 'zero_divide_label'
CONTEXT:  compilation of PL/SQL function "inline_code_block" near line 3

但是,GOTO语句可以从一个异常控制程序中跳转到一个封闭块,上述代码调整为:

修复除零异常后重新执行原预期代码

declare
    a int;
begin
    a = 0;
    <<zero_divide_label>>
    begin
        a = 10/a;
        raise notice '测试结果:%',a;
    exception
        when zero_divide then
            raise notice '块外捕获到异常--》%',sqlerrm;
            a = 1;
            GOTO zero_divide_label;    ----合法的跳转到当前块
    end;
end
--运行结果
NOTICE:  块外捕获到异常--》division by zero
NOTICE:  测试结果:10
ANONYMOUS BLOCK

标签:notice,end,PLSQL,--,捕获,传播,异常,raise
From: https://www.cnblogs.com/kingbase/p/17561071.html

相关文章

  • 异常(exception、try-catch)、泛型
    1.Exception和Error有什么区别?在Java中,所有的异常都有一个共同的祖先java.lang包中的Throwable类。Throwable类有两个重要的子类:Exception:程序本身可以处理的异常,可以通过catch来进行捕获。Exception又可以分为CheckedException(受检查异常,必须处理)和Unc......
  • java基础-异常Exception-day10
    目录1.练习2.异常三联try-catch-finally3.异常的分类3.子类throws的异常小于等于父类的异常4.自定义异常1.练习packagecom.msb01;importjava.util.Scanner;/***@Auther:jack.chen*@Date:2023/9/17-09-17-10:58*@Description:com.msb01*@versi......
  • C++的异常类型与多级catch匹配
    try-catch的用法:try{//可能抛出异常的语句}catch(exceptionTypevariable){//处理异常的语句}我们还遗留下一个问题,就是catch关键字后边的exceptionTypevariable,这节就来详细分析一下。exceptionType是异常类型,它指明了当前的catch可以处理什么类型的异常;varia......
  • python 内置常量,异常
    python内置常量FalseTrueNoneNotImplementedEllipsisdebugsitequit()exit()copyrightcreditslicensepython内置异常所有异常都必须派生自BaseException具体异常AssertionError#当一个assert语句失败的时候AttributeError#属性引用失败或者分配失败引......
  • springmvc中异常配置的两种方式,一种使用注解配置,一种使用控制器配置
    2023-09-16方式一springmvc.xml<!--配置异常处理器--><beanclass="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><propertyname="exceptionMappings"><props>......
  • 异常
    1.异常异常是程序在执⾏过程中出现的错误时或不能显⽰正确的逻辑结果所产⽣的对象,即运⾏时错误异常的处理机制⽤到的5个关键字try:监视⼀段代码在执⾏时是否会发⽣异常catch:如果发⽣了异常则捕获异常对象并处理finally:在程序结束前最后执⾏的代码(出不出不异常都执⾏)th......
  • flask从入门到精通之钩子、异常、context、jinjia模板、过滤器
    一、请求全局钩子【hook】此处的全局钩子,其实就是类似django里面的中间件。也就是只要调用或者注册了,在http请求响应中是必然执行的。在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如:在项目运行开始时,建立数据库连接,或创建连接池;在客户端请求开始时,根据......
  • 【规范】SpringBoot接口返回结果及异常统一处理,这样封装才优雅
    前言......
  • Python学习笔记-Python异常、模块与包
    了解异常什么是异常当检测到一个错误时,Python解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的“异常”,也就是我们常说的BUG。bug单词的诞生早期计算机采用大量继电器工作,马克二型计算机就是这样的。1945年9月9日,下午三点,马克二型计算机无法正常工作了,技术人员试......
  • linux中的异常及信号
    在Linux中,异常处理机制主要由信号和异常处理程序(也称为信号处理程序)两个部分组成。信号是一种软件中断,用于通知进程发生了某些事件或出现了某些异常情况。在Linux中,有许多不同的信号,例如SIGSEGV(非法内存访问)、SIGKILL(强制终止进程)和SIGINT(中断信号,通常由Ctrl+C触发)等。当......