文章概要:

本文对主要就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. C++ 虚基类

    虚基类(Virtual Base Class)在面向对象编程中的作用是解决多重继承中的菱形继承问题(Diamond Inheritance Problem)和共享基类问题(Shared Base Cl ...

  2. 【Azure 存储服务】Azure Data Lake Storage (ADLS) Gen2 GRS Failover是否支持自动切换或者手动切换到灾备的终结点呢?

    问题描述 在Azure的存储服务中,介绍灾备恢复和Storage Account故障转移的文档中,有一句话"Account failover is not supported for sto ...

  3. 【Azure 应用服务】Azure Web App 服务默认支持一些 Weak TLS Ciphers Suite,是否有办法自定义修改呢?

    问题描述 当 Azure Web App 进行安全扫描后,发现依旧支持很多弱TLS加密套件(Weak TLS Ciphers Suite),那么是否有办法来关闭这些弱的加密套件呢? 在Windows ...

  4. 浅入Kubernetes(9):了解组件

    本篇主要介绍 Kubernetes 中的架构组成,在前面我们已经学习到了 kubeadm.kubectl,这两个命令行工具是 k8s 组成之一.而前面在搭建集群时,也学到了 master.worker ...

  5. C++ STL 容器-string类型

    C++ STL 第一部分-容器 STL的介绍 C++的STL分为六大部分 容器分为 容器的概念 容器内元素的条件 1.必须可以复制copy或者搬移move,包括条件是在拷贝和搬移的过程中不存在副作用. ...

  6. 压测中TPS上不去的几种原因及分析?

    1. 服务器资源限制:服务器的硬件资源(如 CPU.内存.磁盘)可能不足以处理大量的请求.在高负载情况下,服务器可能无法及时响应所有的请求,导致 TPS 上不去.解决方法可以考虑升级硬件资源或通过负载 ...

  7. gitlab推送代码触发jenkins构建

    预期:推送devloop或者master分支的代码, 自动执行jenkins 发布测试环境 首先,jenkins中需要安装如下插件 打开一个任务配置,构建触发器中勾选"Build when ...

  8. Kubernetes: kube-controller-manager 源码分析

    0. 前言 在 Kubernetes 架构中,controller manager 是一个永不休止的控制回路组件,其负责控制集群资源的状态.通过监控 kube-apiserver 的资源状态,比较当前 ...

  9. ubuntu16.04 关闭系统的屏幕阅读功能

    在安装audacity的时候,不知道点到哪里,电脑突然就不停的"Chinese Letter",后面仔细听,鼠标点到那里就会读那里文字,键盘输入也是,联想到Android上也有类似 ...

  10. 基于ADS1292芯片的解决方案之源码解析

    接口解析  A 该芯片和主控使用的是SPI接口通信的. SPI接口一般有四根线,确保四根线准确连接是对的. B 该芯片可以有中断模式数据触发,所以,主控mcu需要有外部中断处理流程. //DRDY中断 ...