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編程中的異常處理方式,異常處理的時候能夠經過捕獲異常信息並記錄下來,確保代碼的維護性,也爲問題排查提供參考依據。     也能夠在確保知足業務邏輯的條件下,主動拋出自定義異常的方式終止代碼的執行,來確保業務邏輯的正確性。

相關文章
相關標籤/搜索