T-SQL编程中的异常处理-异常捕获(catch)与抛出异常(throw)
本文出处: http://www.cnblogs.com/wy123/p/6743515.html
T-SQL编程与应用程序一样,都有异常处理机制,比如异常的捕获与异常的抛出(try catch throw),本文简单介绍异常捕获与异常抛出在T-SQL编程中的实际使用 。
异常处理简单说明
异常捕获在应用程序编程中非常常见,提供了处理程序运行时出现的任何意外或异常情况的方法
刚毕业的时候对于异常处理迷茫不解,尤其是catch中又throw,既然catch或者不catch,都会throw,为什么要catch后再throw?catch中到底要做什么处理?
后来接触的多了开始慢慢理解了异常处理这个机制,在应用程序和T-SQL中应该是类似的
可以简单地这样理解:
对于UI层面, 异常捕获,个人理解就是对于可能发生异常的代码段进行捕获处理,给予用户友好的提示信息,
防止应用程序崩溃(或者抛给给用户一个后台代码错误的页面)的一种做法。
如果是底层方法(这个底层可以这么理解A方法调用B方法,B方法又调用C方法,C方法就是底层方法),
异常处理可以是在捕获之后继续抛出给上层调用者,让调用者知道它调用的方法发生了什么问题。
对于发生了异常的代码本身,要记录下来异常的原因,以便于问题的排查。
比如C方法中发生了异常,要告诉调用他的B方法“我发生了异常,异常原因是***”, 这种的话C就要抛出异常,
同时C要记录异常的信息(通过不同方式将上面的异常原因记录下来),供后继排查问题作参考。
以上是理论基础,下面以T-SQL中的异常处理为例,简单介绍一下异常处理方式和要做的事情,T-SQL中的异常处理。
catch块中处理异常信息
首先借助下面两张表来做示例说明。一张产品信息表,有产品Id和价格信息
下面将通过一个新增产品信息的存储过程说明如何进行异常处理
如下是新增产品信息的存储过程,存超过程根据参数,插入到Product表中,
在插入数据的过程中,进行了异常捕获,在catch代码中,有两个操作,
第一步是将异常信息插入ExceptionLog,当然,这个异常信息的格式可以自己定义,第二步抛出异常(throw),就基于上面的理论
首先为什么要记录异常,这个很容易理解,A写的存储过程给B去调用,B调用的时候发生了异常,将异常信息记录下来有利于A去排查异常的具体原因
然后抛出异常,目的是告诉B,执行存储过程的时候产生了异常,你的操作并没有成功执行。
比如下面代码,执行的时候发生了主键冲突异常,throw的作用就是告诉调用者,执行存储过程的时候发生了异常,并将详细的错误信息抛出
当然实际中常见的异常也比较多,比如死锁,主外键冲突,执行超时,没有操作权限等等各种无法估计到的异常,包括记录异常信息的格式,可以自由选择。
此时观察Catch中记录的ExceptionLog信息,也记录了下面
记录下来的异常信息目的是事后排查问题,与上面直接“抛出”的异常信息作用不同的是,
一个是在异常的发生的时候告诉调用者,抛出异常是标明当前执行的代码发生了异常,ExceptionLog记录异常信息是做排查分析异常原因使用
如果不抛出异常,比如如下的代码,注释掉throw语句,等于是在catch块中单纯地记录下来异常之后“吃掉”异常,会出现什么情况
比如在Product表中已经存在Id = 1的记录的情况下,执行如下代码是失败,
但是客户端并没有任何提示,调用方并不知道发生了什么,调用存储过程的时候到底是失败了还是成功了?没有一个明确的答案。
这就是catch中吃掉异常的后果。
因此正常情况下,catch中记录完异常之后,要“抛出”异常,当异常发生的时候,明确地告诉调用方发生了什么问题。
使用throw显式抛出异常
某些情况下需要主动抛出异常的方式来中断逻辑的执行,什么意思?
就是说当前的逻辑,只有在满足一定的条件下才能执行,如果条件不满足,就要明确告诉调用方,你的条件不满足,当前逻辑无法正常执行。
举个例子,还是刚才插入产品信息的存储过程,如下
当插入产品信息的时候,只有产品价格大于0才是有效的产品信息,否则无法插入,
此时就可以通过抛出异常的方式明确地告诉调用者(当然也有其他方式),你的参数不合法,使用throw抛出自定义异常,强制中断代码的执行。
上面的方式只是举个示例说明,正常情况下,调用方传递过来的参数都是经过校验的,不会发生太低级的错误。
当然,实际应用中应该比这个复杂的多,无法保证调用者都是从用户图形界面(UI)发起的,也就是说无法通过直接的预先处理来确保输入信息的合法性
对于类似上面的存储过程
首先无法保证调用方永远传递过来的参数是合法有效的,其次连调用者也无法确保自己的生成的参数的逻辑永远不会发生错误。
此时对于逻辑上要求非常严谨的程序来说,就需要做类似上面主动抛出异常了来中断代码的执行了。
当然上面问题的处理方式也不止这一种,只是说异常处理的应用场景和方式。
throw语句的使用
最后说一下throw语句,
throw是必raiserror更加方便和直观的异常抛出方式,也是推荐的异常处理方式,具体差异网上一大把就不多说了
throw有两种使用方式,抛出自定义异常和直接在catch块中抛出异常。
抛出自定义异常的时候有三个必须参数,下面会细说,catch块中可以直接用throw不需要任何参数的方式抛出捕获到的异常
throw语句的前一句需要一分号结尾,前一句又不能保证一定有分号,
所以可以直接把分号写在throw的前面,比如文中的;throw 50000,'Price can not be less than 0',1 写法
当抛出自定义错误的时候,throw语句有三个参数,参考如下
throw语句安全级别默认为16并且不会被修改,换句话说就是throw语句执行之后将抛出错误,打断当前Session的批处理语句,throw后面的语句将不会执行
第一个参数是错误号,用户自定义错误号要大于50000(50000 to 2147483647)
第二个参数是自定义错误信息内容,可以根据需要自定义
第三个参数是Error State,他的作用是可以标记异常发生的位置,
比如同样是“参数不能小于0”的错误提示,整个存储过程中有可能有两个地方进行同样的校验
就可以在两个地方使用Error State不同分别来抛出异常;
throw 50000,'Price can not be less than 0',
throw 50000,'Price can not be less than 0',,
因为Error State不同,就可以根据具体的Error State更加方便地知道是哪个地方发生了异常,参考
throw语句存储自定义异常到messages系统表
可以将自定义的异常信息加入到sys.messages 系统表中,先加英文的,再加中文的。
然后使用的时候可以使用这个预定义的message,而不是每次写一个字符串
EXEC sp_addmessage
@msgnum = 50001,
@severity = 16,
@msgtext = N'%s can not be less than 0',
@lang = 'us_english'; EXEC sp_addmessage
@msgnum = 50001,
@severity = 16,
@msgtext = N'%s 不能小于0',
@lang = '简体中文';
如下,存储过程中先通过FORMATMESSAGE来格式化异常信息,然后使用throw 50001, @msg, 1;的方式抛出异常
然后在调用存储过程是的时候,如下是异常被触发时候的抛出自定义异常的场景。
总结:本文简单介绍了T-SQL编程中的异常处理方式,异常处理的时候可以通过捕获异常信息并记录下来,确保代码的维护性,也为问题排查提供参考依据。
也可以在确保满足业务逻辑的条件下,主动抛出自定义异常的方式终止代码的执行,来确保业务逻辑的正确性。
T-SQL编程中的异常处理-异常捕获(catch)与抛出异常(throw)的更多相关文章
- T-SQL编程中的异常处理-异常捕获(try catch)与抛出异常(throw)
本文出处: http://www.cnblogs.com/wy123/p/6743515.html T-SQL编程与应用程序一样,都有异常处理机制,比如异常的捕获与异常的抛出(try catch th ...
- Java 编程中关于异常处理的 10 个最佳实践
异常处理是Java 开发中的一个重要部分.它是关乎每个应用的一个非功能性需求,是为了处理任何错误状况,比如资源不可访问,非法输入,空输入等等.Java提供了几个异常处理特性,以try,catch 和 ...
- python异常处理-异常捕获-抛出异常-断言-自定义异常-UDP通信-socketserver模块应用-3
异常捕获 异常:程序在运行过程中出现了不可预知的错误,并且该错误没有对应的处理机制,那么就会以异常的形式表现出来 影响:整个程序无法再正常运行 异常的结构 异常的类型 NameError 异常的信息 ...
- python入门19 异常及异常处理 异常捕获
常见异常举例 """ 一些异常举例:""" '''模块不存在 ModuleNotFoundError: No module named 'd ...
- Task 编程中的异常处理
在 .Net 开发中, 使用 Task . Task<T> 进行异步编程是非常方便的, 但是在处理 Task 产生的异常时, 需要注意一个问题, 比如下面的代码: ? 1 2 3 4 5 ...
- ASP.NET Core Web API中实现全局异常捕获与处理
处理全局异常 HANDLING ERRORS GLOBALLY 在上面的示例中,我们的 action 内部有一个 try-catch 代码块.这一点很重要,我们需要在我们的 action 方法体中处理 ...
- 3.C#/.NET编程中的常见异常(持续更新)
1.Object reference not set to an instance of an object. 未将对象引用(引用)到对象的实例,说白了就是有个对象为null,但是你在用它点出来的各种 ...
- 14.C#/.NET编程中的常见异常(持续更新)
1.Object reference not set to an instance of an object. 未将对象引用(引用)到对象的实例,说白了就是有个对象为null,但是你在用它点出来的各种 ...
- sql编程中流程控制 IF ……THEN……ELSEIF……THEN………END IF
写mysql存储过程应注意的几点: 1.声明变量(declare)时要注意字符集,用变量存储表字段时,表字段与变量的字符编码要一致. 2.mysql的字符合并不能用‘+’号,必须用concat函数. ...
随机推荐
- Swap Nodes in Pairs leetcode
Given a linked list, swap every two adjacent nodes and return its head. For example,Given 1->2-&g ...
- Python全栈开发——Linux命令学习
Linux -- 一切皆文件 pwd: 查看当前所在目录 '/' :根目录 cd : 切换目录 eg.cd / 切换到根目录 ls:查看当前根目录下有几块盘.几个文件 ls -l:查看详细信 ...
- iOS 获取手机型号,系统版本
新添加判断iPhone 7.iPhone 7 Plus ,我手里没有7,判断不对表打我~ FQ找的资料:http://www.iphonehacks.com/download-iphone-ios-f ...
- 九度OJ题目1443:Tr A (JAVA)
题目描述: A为一个方阵,则Tr A表示A的迹(就是主对角线上各项的和),现要求Tr(A^k)%9973. 输入: 数据的第一行是一个T,表示有T组数据. 每组数据的第一行有n(2 <= n & ...
- 微信企业号接收消息(使用SpringMVC)
微信企业号接收消息(使用SpringMVC) 微信企业号接收消息(使用SpringMVC) 将应用设置在回调模式时,企业可以通过回调URL接收员工回复的消息,以及员工关注.点击菜单.上报地理位置等事件 ...
- Python中的元祖Tuple
Python中的元祖和list基本上一样 tuple = () # 表示一个空的元祖 tuple = (50, ) # 元组中只有一个元素的时候,必须在后面加上逗号 无关闭分隔符 任意无符号的对象,以 ...
- echarts柱图自定义为硬币堆叠的形式
看这标题,可能会有一些人不太明白,那么直接上图,就是柱图展示形式如下图(兼容IE8) 要想实现这样展示效果.我们想用echarts直接实现不行的,即使是纹理填充也不可行的,但是我们可以借助echart ...
- 初识 Javascript.02 -- Date日期、Math对象、数据类型转换、字符串、布尔Boolean、逻辑运算符、if else 、三元表达式、代码调试方法、
Date()对象: Date对象用于处理日期和时间. 1.1 Math对象 ◆Math.ceil() 天花板函数 向上取整 只取整数,不足则进1 ◆Math.floor() 地板函数 ...
- parentNode和parentElement区别
parentNode跟parentElement除了前者是w3c标准,后者只ie支持 当父节点的nodeType不是1,即不是element节点的话,它的parentElement就会是null 一般 ...
- YII2.0 ——安装yii2项目
有两种安装方式 第一种:使用composer进行安装 composer global require"fxp/composer-asset-plugin:^1.2.0" compo ...