PLSQL总结-3(异常处理及嵌套块).ppt
《PLSQL总结-3(异常处理及嵌套块).ppt》由会员分享,可在线阅读,更多相关《PLSQL总结-3(异常处理及嵌套块).ppt(82页珍藏版)》请在装配图网上搜索。
PL SQL总结 3 目录 处理异常捕获OracleServer异常捕获用户定义异常识别变量作用域 处理异常 本部分将讲解 在PL SQL代码中包含异常处理代码的优点PL SQL块异常处理部分的目的异常处理指南 处理异常 前面学了如何在PL SQL块中编写声明部分和执行部分 所有要执行的SQL和PL SQL代码都写在执行部分 迄今为止我们假设代码只有编译错误 然而 代码会发生难以预料的运行时错误 本部分学习如何在PL SQL块中处理这些运行时错误 什么是异常 异常是程序的运行时错误 异常会中断程序的正常执行 异常的产生有多种原因 用户输入错误 硬件错误 网页不存在 等等 你使用应用程序和网站时遇到过错误吗 PL SQL中的异常 下例运行正常 但是如果输入的是Korea South而不是RepublicofKorea呢 DECLAREv country namewf countries country name TYPE RepublicofKorea v elevationwf countries highest elevation TYPE BEGINSELECThighest elevationINTOv elevationFROMwf countriesWHEREcountry name v country name DBMS OUTPUT PUT LINE v country name END PL SQL中的异常 DECLAREv country namewf countries country name TYPE RepublicofKorea v elevationwf countries highest elevation TYPE BEGINSELECThighest elevationINTOv elevationFROMwf countriesWHEREcountry name v country name DBMS OUTPUT PUT LINE v country name END PL SQL中的异常 代码没有按预期的运行 没有找到有关Korea South的数据 因为国家名实际上是按RepublicofKorea存储的 这类PL SQL错误称为异常 异常发生时 我们说异常被 抛出 异常被抛出时 异常点之后PL SQL块执行部分的剩余代码不再执行 什么是异常处理代码 异常处理代码定义了异常发生后应当执行的恢复操作 编写代码时 程序员应当预见到代码执行时可能发生的错误的类型 然后为每一种错误编写异常处理代码 异常处理代码是程序员为代码错误编制的处理预案 什么是异常处理代码 程序员使用异常处理代码来处理哪些错误 系统错误 比如磁盘空间耗尽 数据错误 比如 主键值重复 用户错误 比如 数据输入错误 很多其它的可能性 为什么异常处理重要 你能说明为什么异常处理如此重要吗 可能的原因包括 减轻错误对用户的影响 频繁的错误使用户沮丧甚至拒绝使用程序 保护数据库 避免数据丢失或被覆盖 错误消耗大量系统资源 错误发生后 纠正错误代价高昂 用户频繁打电话请求帮助 代码更加易读 因为错误处理代码可在同一个块中的独立部分处理错误 处理PL SQL异常 PL SQL抛出异常 块执行结束但可编写异常处理代码 在块结束前执行最后的操作 异常处理部分以关键字EXCEPTION开始 处理PL SQL异常 异常如果被处理 PL SQL程序就不会突然中断 异常抛出后 控制转到异常处理部分 执行相应的处理代码 之后 PL SQL块正常 成功结束 一个时刻只能发生一个异常 异常发生时 PL SQL在块结束前只执行一个异常处理代码 处理PL SQL异常 点A的代码不会执行 因为SELECT语句失败 处理PL SQL异常 下面是另一示例 块中select语句用于获取John的last name DECLAREv lnameVARCHAR2 15 BEGINSELECTlast nameINTOv lnameFROMemployeesWHEREfirst namelike El DBMS OUTPUT PUT LINE Ellen slastnameis v lname END 然而 因为有多个John所以会产生异常 处理PL SQL异常 下例中异常处理代码用于处理预定义的Oracle服务错误TOO MANY ROWS 下部分将详细学习预定义的Oracle服务错误 DECLAREv lnameemployees last name TYPE BEGINSELECTlast nameINTOv lnameFROMemployeesWHEREfirst namelike El DBMS OUTPUT PUT LINE Ellen slastnameis v lname EXCEPTIONWHENTOO MANY ROWSTHENDBMS OUTPUT PUT LINE Yourselectstatementretrievedmultiplerows Considerusingacursor END 捕获异常 你可通过在PL SQL块的异常处理部分增加相应的处理代码来处理或捕获 trap 任何错误 语法 捕获异常 每个异常处理代码包含一个WHEN子句 其后是异常名 然后是THEN引导的异常处理语句 在EXCEPTION部分可包含任意多个异常处理代码来处理特定的异常 然而 不能为同一个异常编写多个异常处理代码 捕获异常 语法中 exception是预定义的异常名或用户在声明部分定义的异常名statement是一个或多个PL SQL或SQL语句OTHERS是可选的异常处理子句 用于捕获前面没有明确捕获的任何异常 OTHERS关键字 异常处理部分只捕获那些WHEN子句说明的异常 其它任何异常都不会被捕获 除非后面也使用了OTHERS子句 OTHERS子句捕获前面没有捕获的异常 如果使用 OTHERS必须是异常处理最后一个子句 OTHERS关键字 考虑下面的例子 如果程序抛出NO DATA FOUND异常 则执行statement1如果程序抛出TOO MANY ROWS异常 则执行statement2如果程序抛出了其他异常 则执行statement3 捕获异常指南 如果有可能发生错误 就要添加异常处理代码 在计算时 字符串操作时 执行SQL语句时都有可能发生错误 如果有可能 尽量按名称处理异常而不是用OTHERS捕获异常 掌握预定义异常的名称及其产生的原因 用不同的坏数据及其组合测试代码 发现可能出现的错误 在异常处理代码中输出调试信息 仔细考虑每个异常处理代码是需要提交事务 还是撤销事务 或是让事务继续 不管错误多么严重 我们都要使数据库处于一致状态 避免保存任何坏数据 处理异常 本部分讲解了 在PL SQL代码中包含异常处理代码的优点PL SQL块异常处理部分的目的异常处理指南 捕获OracleServer异常 本部分将讲解 Oracle服务异常用户自定义异常显式和隐式抛出的异常捕获预定义的OracleServer异常捕获非预定义的OracleServer错误通过错误代码和错误消息识别异常 捕获OracleServer异常 PL SQL错误处理非常灵活 允许程序员处理用户定义异常和Oracle定义异常 本部分学习预定义和非预定义Oracle服务错误 预定义错误是常见的Oracle错误 为了方便 PL SQL已经为其定义了异常名 非预定义错误使用ORA错误代码和消息 两种错误处理语法不同 但你可在EXCEPTION处理部分捕获所有这两种错误 ExceptionTypes 在PL SQL中处理异常 有两种方式抛出异常 Oracle服务隐式 自动 抛出 Oracle服务发生错误时 异常自动抛出 例如 单行SELECT查询如果没有返回数据 则发生编号ORA 01403的错误 thenPL SQL抛出NO DATA FOUND异常 程序员显式 明确 抛出 根据程序要实现的功能 有时需要显式抛出异常 可通过RAISE语句明确的抛出异常 RAISE语句抛出的异常可以是用户定义的 也可是Oracle预先定义好的 下一部分详细解释 两种Oracle服务错误 Oracle服务发生错误时 相关异常自动抛出 执行部分剩余代码被忽略 在异常处理部分寻找对应异常处理代码 有两种Oracle服务错误 预定义Oracle服务错误 此类错误有预先定义好的异常名 如 错误ORA 01403的异常名为NO DATA FOUND 非预定义Oracle服务错误 此类错误没有预先定义好的异常名 只有形如 ORA nnnnn 的标准错误编号和错误描述消息 可以为此类错误声明一个异常名 从而可以在异常处理部分使用此名称捕获该异常 捕获预定义Oracle服务错误 在异常处理代码中引用预定义的异常名 下面是几个预定义异常的例子 NO DATA FOUNDTOO MANY ROWSINVALID CURSORZERO DIVIDEDUP VAL ON INDEXplsql s06 l02 predefined errors doc文档中给出了部分预定义异常 完整异常列表参看PL SQLUser sGuideandReference 捕获预定义Oracle服务错误 下例中使用了预定义Oracle错误TOO MANY ROWS注意预定义Oracle错误无需声明 直接使用DECLAREv lnameVARCHAR2 15 BEGINSELECTlast nameINTOv lnameFROMemployeesWHEREfirst namelike El DBMS OUTPUT PUT LINE Ellen slastnameis v lname EXCEPTIONWHENTOO MANY ROWSTHENDBMS OUTPUT PUT LINE Yourselectstatementretrievedmultiplerows Considerusingacursor END 捕获多个预定义Oracle服务错误 下例处理了TOO MANY ROWS和NO DATA FOUND异常 并使用OTHERS来处理其它可能的异常 DECLAREv lnameVARCHAR2 15 BEGINSELECTlast nameINTOv lnameFROMemployeesWHEREfirst name John DBMS OUTPUT PUT LINE John slastnameis v lname EXCEPTIONWHENTOO MANY ROWSTHENDBMS OUTPUT PUT LINE Selectstatementfoundmultiplerows WHENNO DATA FOUNDTHENDBMS OUTPUT PUT LINE Selectstatementfoundnorows WHENOTHERSTHENDBMS OUTPUT PUT LINE Anothertypeoferroroccurred END 捕获非预定义Oracle服务错误 非预定义Oracle异常和预定义异常类似 但在PL SQL中没有预定义的名称 它们是标准Oracle服务错误 有ORA 错误编号 在DECLARE部分程序员自己为错误定义一个异常名 并使用PRAGMAEXCEPTION INIT函数将其与ORA 错误编号关联在一起 捕获非预定义Oracle服务错误 要捕获非预定义Oracle服务错误 必须先声明异常 声明的异常是自动抛出的 在PL SQL中 PRAGMAEXCEPTION INIT指示编译器将异常名和Oracle错误编号关联 这样 就可以通过异常名来捕获非预定义Oracle服务错误 并为其提供专门的异常处理代码 非预定义Oracle服务错误 示例BEGININSERTINTOdepartments department id department name VALUES 280 NULL END INSERT语句试图为departments表的department name列插入空值 然而语句失败 因为department name定义为NOTNULL 违反NOTNULL约束这种错误没有预定义好的异常名称 处理这种错误的方法是自己声明异常名并将其与ORA 1400错误编号关联在一起 非预定义Oracle服务错误 1 在声明部分定义一个异常名 非预定义Oracle服务错误 2 使用PRAGMAEXCEPTION INIT函数将异常名和标准Oracle错误编号关联 非预定义Oracle服务错误 3 在异常处理代码中引用前面定义的异常名 异常相关函数 异常发生时 可通过下面两个函数获取相关的错误代码和错误消息 基于错误代码和错误消息可以决定后续操作 SQLERRM返回文本类型的错误消息SQLCODE返回数值类型的错误代码 可赋予NUMBER类型变量 异常相关函数 不能直接在SQL语句中使用SQLCODE或SQLERRM 必须先将其值赋予局部变量 然后在SQL语句中使用变量 如下例所示 捕获OracleServer异常 本部分讲解了 Oracle服务异常用户自定义异常显式和隐式抛出的异常捕获预定义的OracleServer异常捕获非预定义的OracleServer错误通过错误代码和错误消息识别异常 捕获用户定义异常 此部分将讲解 编写PL SQL代码定义用户定义异常编写PL SQL代码抛出异常处理抛出的异常使用RAISE APPLICATION ERROR 捕获用户定义异常 PL SQL处理的另一类错误是用户定义异常 此类错误不是由Oracle服务自动抛出 而是程序员在自己的代码中定义并抛出的 自定义错误的一个例子是非法经理ID INVALID MANAGER ID 也可以为自定义错误定义错误编号和错误消息 异常类型 本部分学习用户定义异常 捕获用户定义异常 PL SQL允许自定义异常 根据应用程序需要定义自己的异常 捕获用户定义异常 需要自定义异常的一个例子是 你需要处理和强调输入数据的错误 例如 假设程序需要提示用户输入部门编号和姓名 用于修改部门数据 DECLAREv nameVARCHAR2 20 Accounting v deptnoNUMBER 27 BEGINUPDATEdepartmentsSETdepartment name v nameWHEREdepartment id v deptno END 如果用户输入不存在的部门编号会怎样 上面代码不会出现Oracle服务错误 你需要自定义异常来提示数据输入的错误 捕获用户定义异常 自定义异常的方法是 1 在声明部分定义异常的名称 2 使用RAISE语句在执行部分显式抛出异常 3 在异常处理部分通过自定义异常名捕获异常 捕获用户定义异常 下面是完整的代码 捕获用户定义异常 1 在声明部分定义异常的名称 语法 exceptionEXCEPTION 其中 exception是异常的名称 捕获用户定义异常 2 使用RAISE语句在执行部分显式抛出异常 语法 RAISEexception 其中 exception是前面定义的异常名 捕获用户定义异常 3 在异常处理部分通过自定义异常名捕获异常 RAISE语句 RAISE语句用于抛出已命名的异常 可以抛出 自定义异常Oracle服务异常 RAISE APPLICATION ERROR 可用RAISE APPLICATION ERROR过程从存储程序中返回给用户自定义的错误消息 使用RAISE APPLICATION ERROR的主要优点是 和RAISE相比 RAISE APPLICATION ERROR允许为自定义的异常指定错误编号和错误消息 错误编号必须在 20000和 20999之间 语法 RAISE APPLICATION ERROR error number是自定义错误编号 自定义的异常错误编号必须在 20000和 20999之间Message是为错误自定义的错误消息 是可长达2 048字节的字符串 TRUE FALSE是可选的Boolean参数 TRUE 此错误在前面出现的所有错误之前显示 FALSE 此错误取代前面出现的所有错误 前面的其它错误不再有提示信息 范围 20000到 20999的错误编号预留给程序员使用 预定义的Oracle服务错误不会使用 RAISE APPLICATION ERROR RAISE APPLICATION ERROR可用于 执行部分异常处理部分 执行部分的RAISE APPLICATION ERROR RAISE APPLICATION ERROR过程为用户显示错误编号和消息 这和Oracle服务错误的处理方式是一致的 DECLAREv mgrPLS INTEGER 123 BEGINDELETEFROMemployeesWHEREmanager id v mgr IFSQL NOTFOUNDTHENRAISE APPLICATION ERROR 20202 Thisisnotavalidmanager ENDIF END 异常部分的RAISE APPLICATION ERROR DECLAREv mgrPLS INTEGER 27 v employee idemployees employee id TYPE BEGINSELECTemployee idintov employee idFROMemployeesWHEREmanager id v mgr DBMS OUTPUT PUT LINE Theemployeewhoworksformanager id v mgr is v employee id EXCEPTIONWHENNO DATA FOUNDTHENRAISE APPLICATION ERROR 20201 Thismanagerhasnoemployees WHENTOO MANY ROWSTHENRAISE APPLICATION ERROR 20202 Toomanyemployeeswerefound END 保留前面的错误 DECLAREv mgrPLS INTEGER 27 v employee idemployees employee id TYPE BEGINSELECTemployee idintov employee idFROMemployeesWHEREmanager id v mgr EXCEPTIONWHENNO DATA FOUNDTHENRAISE APPLICATION ERROR 20201 Thismanagerhasnoemployees true END RAISE APPLICATION ERROR与自定义异常合用 捕获用户定义异常 此部分讲解了 编写PL SQL代码定义用户定义异常编写PL SQL代码抛出异常处理抛出的异常使用RAISE APPLICATION ERROR 识别变量作用域 此部分将讲解 描述在嵌套块中变量的作用域 使用标签限定嵌套块中的变量描述异常的作用域识别嵌套块中异常的作用域问题描述异常在嵌套块中的传播方式及其影响 识别变量作用域 前面已学习过嵌套块 变量的作用域和异常的传播 理解了如何正确处理异常 本部分先复习前面知识 然后再讲述新的内容 命名异常是一种PL SQL变量 要正确处理异常 需要理解异常变量的作用域和可见性 这在使用嵌套块时尤其重要 复习嵌套块 下例有外层 父 块 蓝色显示 和嵌套 子 块 红色显示 变量v outer variable在父块中定义 变量v inner variable在子块中定义 复习变量作用域 变量作用域是变量在其中可被访问和使用的一个块或多个块 PL SQL中 变量作用域是其定义所在块及其所有子块 下例两个变量的作用域是什么 复习变量作用域 阅读下面代码 每个变量的作用域是什么 复习变量作用域 下面代码为什么出错 复习变量作用域 下面代码正确吗 为什么 PL SQL怎样寻找变量 在块中使用变量时 PL SQL先在当前块中寻找该变量 局部变量 如果未找到 PL SQL继续在父块中寻找 如果还未找到 PL SQL在父块的父块中寻找 嵌套可有三层或更多层 依此类推 下例中有三层嵌套 三层嵌套示例 每个变量的作用域是什么 复习变量命名 下面变量声明对不对 以上声明合法 但在子块中无法访问父块定义的变量v myvar 复习变量命名 变量v date of birth声明了两次 DBMS OUTPUT PUT LINE语句中引用的是哪个v date of birth 复习变量可见范围 变量可见范围是变量作用域中 不加限定符就可使用变量的部分 下面每个变量的可见范围是什么 复习变量可见范围 父块的v date of birth变量作用域包括子块 此变量在父块中可见 然而 该变量在子块中不可见 被隐藏 因为子块中有一个同名的局部变量 变量v father name在父子块中都可见 变量v child name只在子块中可见 怎样才能在子块中引用父块定义的变量v date of birth呢 复习块标签 可使用 语法为块加标签 然后通过标签使用在作用域内但被隐藏的变量 下例中 父块标签为outer 不仅父块 任何块都可加标签 通过块标签使用被隐藏变量 通过使用标签outer限定变量v date of birth 在子块中就可输出显示父亲的生日了 嵌套块中的异常处理 异常处理方式有两种 在发生异常的块处理 捕获 该异常将异常传递给调用环境 比如其父块 传播异常到父块 如果异常自子块的执行部分抛出 子块无相应处理代码 PL SQL子块以失败结束 异常传递给其父块 传播异常到父块 下例中 子块执行时产生了一个异常 子块EXCEPTION部分没有处理此异常 子块失败结束 PL SQL将异常传递给父块 父块EXCEPTION部分成功处理此异常 从子块向外传递异常 如果PL SQL产生异常 而当前块没有捕获该异常异常连续传递给上层块 直到找到相应异常处理程序 异常传递给上层块时 当前块剩余执行代码被跳过 不再执行 这样做的优点是在块中处理此块可以处理的异常 将更一般的异常处理 如WHENOTHERS 交给上层块去 下面是一个例子 从子块向外传递预定义异常 不存在编号999的员工 下面代码执行结果是什么 从子块向外传递用户定义的异常 下面代码执行结果怎样 异常名的作用域 预定义Oracle服务异常如NO DATA FOUND TOO MANY ROWS 以及OTHERS 不需要用户声明 可在任何块中使用 抛出或捕获 用户命名的异常 非预定义Oracle服务异常和自定义异常 是程序员定义的EXCEPTION类型的变量其作用域和其它变量遵循相同规则 因此 子块声明的自定义异常不能在父块中使用 识别变量作用域 此部分讲解了 描述在嵌套块中变量的作用域 使用标签限定嵌套块中的变量描述异常的作用域识别嵌套块中异常的作用域问题描述异常在嵌套块中的传播方式及其影响- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- PLSQL 总结 异常 处理 嵌套
装配图网所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
关于本文