1. 程式人生 > >關於MySQL異常捕捉那些事兒

關於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/)。

異常捕捉原因

儲存程式執行過程中對於一些異常需要特殊處理,如退出當前執行程式或者繼續執行等,而這些異常需要先捕捉而後處理。

異常捕捉準備知識之錯誤資訊的認識

  1. 當客戶端執行緒向MySQL伺服器提交命令後,執行是否成功,伺服器端都會返回其相關判斷性資料。若是執行過程中出錯了,MySQL會返回兩類資訊:
    A. MySQL特殊的錯誤編碼(如1146),是一個整數型別的程式碼,這些錯誤編碼並不適用於其他的資料庫產品;
    B. MySQL的SQL狀態值,由5個字元組成(如42S02),該值支援ANSI SQL、ODBC或其他標準協議,並不是所有的MySQL返回的錯誤資訊都有SQL狀態值,對於沒有SQL狀態值使用‘HY000’代替。

  2. 對於執行過程中的錯誤返回的錯誤編碼、SQL狀態值以及更詳細的錯誤描述資訊,MySQL提供C API函式,如下:
    A. 返回MySQL錯誤編碼的API函式:mysql_errno();
    B. 返回MySQL SQL狀態值的API函式:mysql_sqlstate();
    C. 返回MySQL錯誤描述資訊的API函式:mysql_error()。

  3. 對於預處理語句,相應的錯誤函式有mysql_stmt_errno()、mysql_stmt_sqlstate()、mysql_stmt_error()。

  4. Errors/Warnings/Notes的數量可以通過呼叫mysql_warning_count()函式獲得。

  5. 對於MySQL執行過程中的錯誤返回的SQL狀態值前兩個字元的含義如下:
    A. ‘00’代表MySQL執行成功;
    B. ‘01’代表MySQL執行成功,但是存在警告資訊;
    C. ‘02’代表MySQL沒有獲得結果,遊標移動到記錄結果集的最後或者SELECT … INTO var_list沒有取到資料,就會觸發此類錯誤資訊;
    D. 前兩個字元大於‘02’的SQL狀態值統稱為異常,使用EXCEPTION標識。

  6. MySQL的錯誤編碼、SQL狀態值及資訊
    http://dev.mysql.com/doc/refman/5.6/en/error-messages-server.html

定義異常

  1. 語法

  2. 特別說明
    A. 異常的定義必須出現在遊標或異常處理定義之前;
    B. 不必要處理mysql_error_code為0或者sqlstate_value以‘00’開頭的情況,因為它們標識著MySQL執行成功。

定義異常處理

  1. 語法

  2. 特別說明
    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狀態值

  3. 對於沒有定義異常處理的異常,MySQL採取的措施如下:
    A. 對於SQLEXCEPTION的異常,則程式在觸發異常的位置終止;
    B. 對於SQLWARNING的異常,則程式在觸發異常之後繼續執行;
    C. 對於NOT FOUND的異常,正常情況下程式在觸發異常之後繼續執行,當使用SIGNAL/RESIGNAL處理之後,程式則在觸發異常的位置終止。

偽裝錯誤資訊之SIGNAL

  1. 語法

  2. 特別說明
    A. SIGNAL語句的執行不需要任何特殊許可權;
    B. condition_value可以是SQL狀態值或DECLARE … CONDITION定義的異常名稱,注意此處不可使用錯誤編號,否則會導致ERROR 1646 (HY000): SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE;

  3. SIGNAL語句實戰演練
    A. 儲存過程示例

    B. 執行結果

    C. 結果分析
    當divisor=1時,根據其執行結果紅框中的SQLSTATE值可知觸發的是第一個my_error異常,是由最後一條SIGNAL my_error;語句觸發的;
    當divisor=0時,根據其執行結果紅框中的SQLSTATE值可知觸發的是第二個my_error異常,是由第一個SIGNAL my_error;語句觸發的;

偽裝錯誤資訊之RESIGNAL

  1. 語法

  2. 特別說明
    A. RESINGAL語句和SIGNAL語句作用相似;
    B. RESIGNAL語句的執行不需要任何特殊的許可權;
    C. condition_value可以是SQL狀態值或DECLARE … CONDITION定義的異常名稱,注意此處不可使用錯誤編號,否則會導致ERROR 1646 (HY000): SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE;

  3. RESIGNAL的幾種用法
    A. 僅使用RESIGNAL作為單獨的SQL語句
    B. RESIGNAL+SET語句一起使用
    C. RESIGNAL+condition_value+SET語句一起使用

異常捕捉實戰演練

  1. 特別說明
    A. 以定義異常處理中的三種處理方式CONTINUE/EXIT/UNDO為不同點,演示如何定義異常和異常處理;
    B. 實戰演練以儲存過程為示例;
    C. 示例中的異常觸發條件為:SELECT * FROM t;在執行示例的資料庫中並不存在t表。

  2. 實戰演練

A. 異常處理方式為CONTINUE
儲存過程示例:

儲存過程結果:

結果分析:
call sp_test的結果中包含三條語句,第一條語句為SELECT b的輸出;然後‘SELECT * FROM t’觸發錯誤編號為1146的異常,此時儲存過程中存在對錯誤編號為1146的異常處理,所以第二條語句為異常處理語句塊中SELECT a的輸出;由於錯誤編號為1146的異常處理為CONTINUE,故異常處理後,回到觸發異常的下一個語句位置,繼續執行,所以第三條語句為SELECT c的輸出。

B. 異常處理方式為EXIT
儲存過程示例:

儲存過程結果:

結果分析:
call sp_test的結果中包含兩條語句,第一條語句和第二條語句的輸出與‘異常處理為CONTINUE’的第一條和第二條語句輸出分析一致;由於錯誤編號為1146的異常處理為EXIT,故異常處理完畢後,跳出當前程式,即該示例中SELECT c並不會被執行。

C. 異常處理方式為UNDO
儲存過程示例:

儲存過程結果:

結果分析:
由於異常處理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/