T-SQL编程中的异常处理-异常捕获(try catch)与抛出异常(throw)

 

本文出处: http://www.cnblogs.com/wy123/p/6743515.html 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要记录异常的信息(经过不一样方式将上面的异常缘由记录下来),供后继排查问题做参考。less

  以上是理论基础,下面以T-SQL中的异常处理为例,简单介绍一下异常处理方式和要作的事情,T-SQL中的异常处理。spa

 

catch块中处理异常信息3d

  首先借助下面两张表来作示例说明。一张产品信息表,有产品Id和价格信息code

  

  下面将经过一个新增产品信息的存储过程说明如何进行异常处理
  以下是新增产品信息的存储过程,存超过程根据参数,插入到Product表中,htm

  

  在插入数据的过程当中,进行了异常捕获,在catch代码中,有两个操做,
  第一步是将异常信息插入ExceptionLog,固然,这个异常信息的格式能够本身定义,第二步抛出异常(throw),就基于上面的理论
  首先为何要记录异常,这个很容易理解,A写的存储过程给B去调用,B调用的时候发生了异常,将异常信息记录下来有利于A去排查异常的具体缘由
  而后抛出异常,目的是告诉B,执行存储过程的时候产生了异常,你的操做并无成功执行。
  好比下面代码,执行的时候发生了主键冲突异常,throw的做用就是告诉调用者,执行存储过程的时候发生了异常,并将详细的错误信息抛出blog

  固然实际中常见的异常也比较多,好比死锁,主外键冲突,执行超时,没有操做权限等等各类没法估计到的异常,包括记录异常信息的格式,能够自由选择。字符串

  

  此时观察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',1
       throw 50000,'Price can not be less than 0',2
       由于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编程中的异常处理方式,异常处理的时候能够经过捕获异常信息并记录下来,确保代码的维护性,也为问题排查提供参考依据。     也能够在确保知足业务逻辑的条件下,主动抛出自定义异常的方式终止代码的执行,来确保业务逻辑的正确性。