文章概要:

本文对主要就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

PLSQL的异常传播的更多相关文章

  1. PLSQL_Oracle Exception异常分类、异常抛出、异常处理、异常传播(概念)

    2014-06-03 Created By BaoXinjian

  2. python中如何通过报错信息定位问题(异常传播轨迹)

    class SelfException(Exception): pass def main(): firstMethod() def firstMethod(): secondMethod() def ...

  3. WCF异常传播

    传送至客户端的异常肯定是CommunitionException类型,包括一般的通信过程中出错而引发的CommunicationException类型,System.IdentityModel.Sel ...

  4. plsql数据库异常---plsql 登录后,提示数据库字符集(AL32UTF8)和客户端字符集(ZHS16GBK)不一致

    今天遇到这个问题网上搜了一下答案找到了 转贴 http://blog.csdn.net/lidew521/article/details/8546155 plsql 登录后提示: Database c ...

  5. [转贴] 从零开始学C++之异常(二):程序错误、异常(语法、抛出、捕获、传播)、栈展开

    一.程序错误 编译错误,即语法错误.程序就无法被生成运行代码. 运行时错误 不可预料的逻辑错误 可以预料的运行异常 例如: 动态分配空间时可能不会成功 打开文件可能会失败 除法运算时分母可能为0 整数 ...

  6. .Net程序员学用Oracle系列(27):PLSQL 之游标、异常和事务

    1.游标 1.1.游标属性 1.2.隐式游标 1.3.游标处理及案例 2.异常 2.1.异常类别 2.2.异常函数 2.3.异常处理及案例 3.事务 3.1.开始事务.结束事务 3.2.自治事务 3. ...

  7. Netty源码分析第4章(pipeline)---->第6节: 传播异常事件

    Netty源码分析第四章: pipeline 第6节: 传播异常事件 讲完了inbound事件和outbound事件的传输流程, 这一小节剖析异常事件的传输流程 首先我们看一个最最简单的异常处理的场景 ...

  8. [Google Guava] 1.5-Throwables:简化异常和错误的传播与检查

    原文链接 译者: 沈义扬 异常传播 有时候,你会想把捕获到的异常再次抛出.这种情况通常发生在Error或RuntimeException被捕获的时候,你没想捕获它们,但是声明捕获Throwable和E ...

  9. 事件和异常的传播 · 农场主的黑科技.

    inBound事件的传播 何为inBound事件以及ChannelInboundHandler ChannelRead事件的传播ChannelRead是典型的inbound事件,以他为例了解inbou ...

  10. 『无为则无心』Python函数 — 39、Python中异常的传播

    目录 1.异常的传播 2.如何处理异常 1.异常的传播 当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播.如果函数中没有对异常进行处理,则异常会继续向函数调用者传播.如果函数调 ...

随机推荐

  1. diffstat命令

    diffstat命令 diffstat命令根据diff的比较结果,统计各文件的插入.删除.修改等差异计量. 语法 diffstat [options] [files] 参数 -c: 输出的每一行都以# ...

  2. spring源码学习之设计模式

    目录 1.策略模式 2.观察者模式 3.装饰者模式 4.工厂模式 工厂方法模式 抽象工厂模式 工厂方法和抽象工厂的异同 5.单例模式 6.适配器模式与外观模式 适配器模式 外观模式 7.模板方法模式 ...

  3. 在Hexo中引入本地图片的实现

    实现步骤 第一步:修改项目根目录下的_config.yml文件参数post_asset_folder值为true. # 开始使用本地静态资源 post_asset_folder: true 第二步:安 ...

  4. https://editor.csdn.net/md/?articleId=131348876

    前言   前面搭建了基础环境,在使用统信UOS系统的相关行业也是不能上网的,但是可以传递压缩包,为了很好的方便相关从业人员工作,特将此种方式流程分享出来.(与国产银河麒麟不同)  本篇文章的重点就是离 ...

  5. MongoDB的安装及启动

    下载地址 https://www.mongodb.com/try/download/community 安装步骤 自定义安装目录 配置环境 下面是你安装后的mongodb的目录 在电脑的环境变量Pat ...

  6. 【Azure 服务总线】查看Service Bus中消息多次发送的日志信息,消息是否被重复消费

    问题描述 使用Service Bus,发现消息被重复消费.如果要查看某一条消息的具体消费情况,需要那些消息的属性呢? 问题解答 使用Azure Service Bus,当消费发送到服务端后,就会生产相 ...

  7. 【Azure 应用服务】遇见“无法创建hybrid connection for App Service”的解决办法

    Hybrid Connection (混合连接) 在两个联网应用程序之间启用了双向.请求-响应和二进制流通信以及简单的数据报流.通过混合连接,可以实现应用部署在公网环境中,而数据库保存在本地私网环境中 ...

  8. 【Azure 应用服务】添加自定义域时,Domain ownership 验证无法通过 

    问题描述 在Azure App Service添加自定义域名时,遇见了Domain ownership 验证无法通过的问题? 问题解决 因为DNS中配置App Service默认域名和自定义域名的CN ...

  9.  liunx上安装django ,启动uwsgi ,语音播报python实现过程

    由于需要做一个语音播报实现,用到的技术是python  ,需要事先搭环境,安装uwsgi  djagno环境,以下内容为百度上找到的好一点的内容,确实照着做成功了,转载一下,下次更好找资料 liunx ...

  10. 适用于AbpBoilerplate的RocketChat Api库

    RocketChat 适用于AbpBoilerplate的RocketChat Api库 Rocket.Chat 是一个免费.开源.可扩展.高度可定制且安全的平台,可让您与团队进行交流和协作.共享文件 ...