關於MySQL異常捕捉那些事兒
本系列文章主要介紹如何捕捉處理MySQL異常以及實戰演練展示,參考於MySQL5.6官方文件(http://dev.mysql.com/doc/refman/5.6/en/index.html) 和 ZHDBA官網之MySQL資料庫的例外處理測試(http://www.zhdba.com/mysqlops/2013/08/31/mysql-handler-2/)。
異常捕捉原因
儲存程式執行過程中對於一些異常需要特殊處理,如退出當前執行程式或者繼續執行等,而這些異常需要先捕捉而後處理。
異常捕捉準備知識之錯誤資訊的認識
-
當客戶端執行緒向MySQL伺服器提交命令後,執行是否成功,伺服器端都會返回其相關判斷性資料。若是執行過程中出錯了,MySQL會返回兩類資訊:
A. MySQL特殊的錯誤編碼(如1146),是一個整數型別的程式碼,這些錯誤編碼並不適用於其他的資料庫產品;
B. MySQL的SQL狀態值,由5個字元組成(如42S02),該值支援ANSI SQL、ODBC或其他標準協議,並不是所有的MySQL返回的錯誤資訊都有SQL狀態值,對於沒有SQL狀態值使用‘HY000’代替。 -
對於執行過程中的錯誤返回的錯誤編碼、SQL狀態值以及更詳細的錯誤描述資訊,MySQL提供C API函式,如下:
A. 返回MySQL錯誤編碼的API函式:mysql_errno();
B. 返回MySQL SQL狀態值的API函式:mysql_sqlstate();
C. 返回MySQL錯誤描述資訊的API函式:mysql_error()。 -
對於預處理語句,相應的錯誤函式有mysql_stmt_errno()、mysql_stmt_sqlstate()、mysql_stmt_error()。
-
Errors/Warnings/Notes的數量可以通過呼叫mysql_warning_count()函式獲得。
-
對於MySQL執行過程中的錯誤返回的SQL狀態值前兩個字元的含義如下:
A. ‘00’代表MySQL執行成功;
B. ‘01’代表MySQL執行成功,但是存在警告資訊;
C. ‘02’代表MySQL沒有獲得結果,遊標移動到記錄結果集的最後或者SELECT … INTO var_list沒有取到資料,就會觸發此類錯誤資訊;
D. 前兩個字元大於‘02’的SQL狀態值統稱為異常,使用EXCEPTION標識。 -
MySQL的錯誤編碼、SQL狀態值及資訊
http://dev.mysql.com/doc/refman/5.6/en/error-messages-server.html
定義異常
-
特別說明
A. 異常的定義必須出現在遊標或異常處理定義之前;
B. 不必要處理mysql_error_code為0或者sqlstate_value以‘00’開頭的情況,因為它們標識著MySQL執行成功。
定義異常處理
-
特別說明
A. statement可以是簡單的SQL語句如SET val_name=value,也可以由BEGIN 和END組成的複合語句;
B. 異常處理的定義必須出現在變數或異常定義之後;
C. handler_action表明觸發異常後如何處理:
CONTINUE:觸發異常後,待執行完處理異常部分的語句體之後,回到觸發異常的下一個語句位置,繼續向下執行;
EXIT:觸發異常後,待執行完處理異常部分的語句體之後,退出當前程式;
UNDO:不支援,建立時會出現語法錯誤。
D. condition_value表示需要處理的異常,包括如下異常值:
MySQL錯誤編碼或SQL狀態值
DECLARE … CONDITION定義的異常名稱
SQLWARNING,表示以‘01’開頭的SQL狀態值
NOT FOUND,表示以‘02’開頭的SQL狀態值
SQLEXCEPTION,表示以大於‘02’開頭的SQL狀態值 -
對於沒有定義異常處理的異常,MySQL採取的措施如下:
A. 對於SQLEXCEPTION的異常,則程式在觸發異常的位置終止;
B. 對於SQLWARNING的異常,則程式在觸發異常之後繼續執行;
C. 對於NOT FOUND的異常,正常情況下程式在觸發異常之後繼續執行,當使用SIGNAL/RESIGNAL處理之後,程式則在觸發異常的位置終止。
偽裝錯誤資訊之SIGNAL
-
特別說明
A. SIGNAL語句的執行不需要任何特殊許可權;
B. condition_value可以是SQL狀態值或DECLARE … CONDITION定義的異常名稱,注意此處不可使用錯誤編號,否則會導致ERROR 1646 (HY000): SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE; -
SIGNAL語句實戰演練
A. 儲存過程示例
B. 執行結果
C. 結果分析
當divisor=1時,根據其執行結果紅框中的SQLSTATE值可知觸發的是第一個my_error異常,是由最後一條SIGNAL my_error;語句觸發的;
當divisor=0時,根據其執行結果紅框中的SQLSTATE值可知觸發的是第二個my_error異常,是由第一個SIGNAL my_error;語句觸發的;
偽裝錯誤資訊之RESIGNAL
-
特別說明
A. RESINGAL語句和SIGNAL語句作用相似;
B. RESIGNAL語句的執行不需要任何特殊的許可權;
C. condition_value可以是SQL狀態值或DECLARE … CONDITION定義的異常名稱,注意此處不可使用錯誤編號,否則會導致ERROR 1646 (HY000): SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE; -
RESIGNAL的幾種用法
A. 僅使用RESIGNAL作為單獨的SQL語句
B. RESIGNAL+SET語句一起使用
C. RESIGNAL+condition_value+SET語句一起使用
異常捕捉實戰演練
-
特別說明
A. 以定義異常處理中的三種處理方式CONTINUE/EXIT/UNDO為不同點,演示如何定義異常和異常處理;
B. 實戰演練以儲存過程為示例;
C. 示例中的異常觸發條件為:SELECT * FROM t;在執行示例的資料庫中並不存在t表。 -
實戰演練
結果分析:
call sp_test的結果中包含三條語句,第一條語句為SELECT b的輸出;然後‘SELECT * FROM t’觸發錯誤編號為1146的異常,此時儲存過程中存在對錯誤編號為1146的異常處理,所以第二條語句為異常處理語句塊中SELECT a的輸出;由於錯誤編號為1146的異常處理為CONTINUE,故異常處理後,回到觸發異常的下一個語句位置,繼續執行,所以第三條語句為SELECT c的輸出。
結果分析:
call sp_test的結果中包含兩條語句,第一條語句和第二條語句的輸出與‘異常處理為CONTINUE’的第一條和第二條語句輸出分析一致;由於錯誤編號為1146的異常處理為EXIT,故異常處理完畢後,跳出當前程式,即該示例中SELECT c並不會被執行。
結果分析:
由於異常處理UNDO方式不被支援,故建立時會報錯。
轉:自:
https://wing324.github.io/2015/10/02/%E5%85%B3%E4%BA%8EMySQL%E5%BC%82%E5%B8%B8%E6%8D%95%E6%8D%89%E9%82%A3%E4%BA%9B%E4%BA%8B%E5%84%BF/