如何使用MySQL處理程序來處理在存儲過程當中遇到的異常或錯誤。html
當存儲過程當中發生錯誤時,重要的是適當處理它,例如:繼續或退出當前代碼塊的執行,併發出有意義的錯誤消息。mysql
MySQL提供了一種簡單的方法來定義處理從通常條件(如警告或異常)到特定條件(例如特定錯誤代碼)的處理程序。sql
要聲明一個處理程序,您可使用DECLARE HANDLER
語句以下:併發
DECLARE action HANDLER FOR condition_value statement;
若是條件的值與condition_value
匹配,則MySQL將執行statement
,並根據該操做繼續或退出當前的代碼塊。yii
操做(action
)接受如下值之一:spa
CONTINUE
:繼續執行封閉代碼塊(BEGIN ... END
)。EXIT
:處理程序聲明封閉代碼塊的執行終止。condition_value
指定一個特定條件或一類激活處理程序的條件。condition_value
接受如下值之一:code
SQLSTATE
值或者它能夠是SQLWARNING
,NOTFOUND
或SQLEXCEPTION
條件,這是SQLSTATE
值類的簡寫。NOTFOUND
條件用於遊標或SELECT INTO variable_list
語句。SQLSTATE
值相關聯的命名條件。該語句能夠是一個簡單的語句或由BEGIN
和END
關鍵字包圍的複合語句。htm
咱們來看幾個聲明處理程序的例子。blog
如下處理程序意味着若是發生錯誤,則將has_error
變量的值設置爲1
並繼續執行。get
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET has_error = 1;
如下是另外一個處理程序,若是發生錯誤,回滾上一個操做,發出錯誤消息,並退出當前代碼塊。 若是在存儲過程的BEGIN END
塊中聲明它,則會當即終止存儲過程。
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; SELECT 'An error has occurred, operation rollbacked and the stored procedure was terminated'; END;
如下處理程序若是沒有更多的行要提取,在光標或SELECT INTO語句的狀況下,將no_row_found
變量的值設置爲1
並繼續執行。
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_row_found = 1;
如下處理程序若是發生重複的鍵錯誤,則會發出MySQL錯誤1062
。 它發出錯誤消息並繼續執行。
DECLARE CONTINUE HANDLER FOR 1062 SELECT 'Error, duplicate key occurred';
首先,爲了更好地演示,咱們建立一個名爲article_tags
的新表:
USE testdb; CREATE TABLE article_tags( article_id INT, tag_id INT, PRIMARY KEY(article_id,tag_id) );
article_tags
表存儲文章和標籤之間的關係。每篇文章可能有不少標籤,反之亦然。 爲了簡單起見,咱們不會在article_tags
表中建立文章(article
)表和標籤(tags
)表以及外鍵。
接下來,建立一個存儲過程,將文章的id
和標籤的id
插入到article_tags
表中:
USE testdb; DELIMITER $$ CREATE PROCEDURE insert_article_tags(IN article_id INT, IN tag_id INT) BEGIN DECLARE CONTINUE HANDLER FOR 1062 SELECT CONCAT('duplicate keys (',article_id,',',tag_id,') found') AS msg; -- insert a new record into article_tags INSERT INTO article_tags(article_id,tag_id) VALUES(article_id,tag_id); -- return tag count for the article SELECT COUNT(*) FROM article_tags; END$$ DELIMITER ;
而後,經過調用insert_article_tags
存儲過程,爲文章ID爲1
添加標籤ID:1
,2
和3
,以下所示:
CALL insert_article_tags(1,1); CALL insert_article_tags(1,2); CALL insert_article_tags(1,3);
以後,嘗試插入一個重複的鍵來檢查處理程序是否真的被調用。
CALL insert_article_tags(1,3);
執行上面查詢語句,獲得如下結果
mysql> CALL insert_article_tags(1,3); +----------------------------+ | msg | +----------------------------+ | duplicate keys (1,3) found | +----------------------------+ 1 row in set +----------+ | COUNT(*) | +----------+ | 3 | +----------+ 1 row in set Query OK, 0 rows affected
執行後會收到一條錯誤消息。 可是,因爲咱們將處理程序聲明爲CONTINUE
處理程序,因此存儲過程繼續執行。所以,最後得到了文章的標籤計數值爲:3
。
若是將處理程序聲明中的CONTINUE
更改成EXIT
,那麼將只會收到一條錯誤消息。以下查詢語句
DELIMITER $$ CREATE PROCEDURE insert_article_tags_exit(IN article_id INT, IN tag_id INT) BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION SELECT 'SQLException invoked'; DECLARE EXIT HANDLER FOR 1062 SELECT 'MySQL error code 1062 invoked'; DECLARE EXIT HANDLER FOR SQLSTATE '23000' SELECT 'SQLSTATE 23000 invoked'; -- insert a new record into article_tags INSERT INTO article_tags(article_id,tag_id) VALUES(article_id,tag_id); -- return tag count for the article SELECT COUNT(*) FROM article_tags; END $$ DELIMITER ;
執行上面查詢語句,獲得如下結果
mysql> CALL insert_article_tags_exit(1,3); +-------------------------------+ | MySQL error code 1062 invoked | +-------------------------------+ | MySQL error code 1062 invoked | +-------------------------------+ 1 row in set Query OK, 0 rows affected
若是使用多個處理程序來處理錯誤,MySQL將調用最特定的處理程序來處理錯誤。
錯誤老是映射到一個MySQL錯誤代碼,由於在MySQL中它是最具體的。 SQLSTATE
能夠映射到許多MySQL錯誤代碼,所以它不太具體。 SQLEXCPETION
或SQLWARNING
是SQLSTATES
類型值的縮寫,所以它是最通用的。
假設在insert_article_tags_3
存儲過程當中聲明三個處理程序,以下所示:
DELIMITER $$ CREATE PROCEDURE insert_article_tags_3(IN article_id INT, IN tag_id INT) BEGIN DECLARE EXIT HANDLER FOR 1062 SELECT 'Duplicate keys error encountered'; DECLARE EXIT HANDLER FOR SQLEXCEPTION SELECT 'SQLException encountered'; DECLARE EXIT HANDLER FOR SQLSTATE '23000' SELECT 'SQLSTATE 23000'; -- insert a new record into article_tags INSERT INTO article_tags(article_id,tag_id) VALUES(article_id,tag_id); -- return tag count for the article SELECT COUNT(*) FROM article_tags; END $$ DELIMITER ;
咱們嘗試經過調用存儲過程將重複的鍵插入到article_tags
表中:
CALL insert_article_tags_3(1,3);
以下,能夠看到MySQL錯誤代碼處理程序被調用。
mysql> CALL insert_article_tags_3(1,3); +----------------------------------+ | Duplicate keys error encountered | +----------------------------------+ | Duplicate keys error encountered | +----------------------------------+ 1 row in set Query OK, 0 rows affected
從錯誤處理程序聲明開始,以下
DECLARE EXIT HANDLER FOR 1051 SELECT 'Please create table abc first'; SELECT * FROM abc;
1051
號是什麼意思? 想象一下,你有一個大的存儲過程代碼使用了好多相似這樣的數字; 這將成爲維護代碼的噩夢。
幸運的是,MySQL爲咱們提供了聲明一個命名錯誤條件的DECLARE CONDITION
語句,它與條件相關聯。
DECLARE CONDITION
語句的語法以下:
DECLARE condition_name CONDITION FOR condition_value;
condition_value
能夠是MySQL錯誤代碼,例如:1015
或SQLSTATE
值。 condition_value
由condition_name
表示。
聲明後,能夠參考condition_name
,而不是參考condition_value
。
因此能夠重寫上面的代碼以下:
DECLARE table_not_found CONDITION for 1051; DECLARE EXIT HANDLER FOR table_not_found SELECT 'Please create table abc first'; SELECT * FROM abc;
這段代碼比之前的代碼顯然更可讀。
請注意,條件聲明必須出如今處理程序或遊標聲明以前