首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL 存儲過程錯誤處理機制深度解析:HANDLER 優先級與命名條件

     編輯:MySQL 綜合教學

MySQL 存儲過程錯誤處理機制深度解析:HANDLER 優先級與命名條件

MySQL 提供靈活的 DECLARE HANDLER 機制,支援針對具體錯誤碼、SQLSTATE、條件類別 (SQLWARNING/NOT FOUND/SQLEXCEPTION) 甚至自定義命名條件進行捕獲。掌握其優先級規則與最佳實踐,能構建健壯的資料庫層錯誤處理體系。

一、HANDLER 語法全景

DECLARE {CONTINUE | EXIT | UNDO} HANDLER FOR condition_value[,...] statement;

-- condition_value 六大來源:
-- 1. MySQL 錯誤碼 (數字,如 1062)
-- 2. SQLSTATE 'HY000' (標準 5 字元)
-- 3. 命名條件 (DECLARE ... CONDITION FOR ...)
-- 4. SQLWARNING (所有 01 開頭 SQLSTATE)
-- 5. NOT FOUND (所有 02 開頭 SQLSTATE,游標/SELECT INTO 無數據)
-- 6. SQLEXCEPTION (除 00/01/02 外所有 SQLSTATE,即真正的錯誤)

二、動作類型差異

動作行為默認場景
CONTINUE執行 statement 後繼續執行後續語句SQLWARNING, NOT FOUND
EXIT執行 statement 後退出當前 BEGIN...END 區塊SQLEXCEPTION
UNDO回滾前面操作 (MySQL 暫不支援)—

三、優先級規則:具體優於泛化

當多個 HANDLER 同時匹配同一錯誤時,MySQL 按照 具體程度 選擇最優先的:

  1. MySQL 錯誤碼 (最具體,一一對應)
  2. SQLSTATE (一個 SQLSTATE 可對應多個錯誤碼)
  3. SQLEXCEPTION / SQLWARNING / NOT FOUND (最泛化,類別捕獲)

驗證範例

CREATE PROCEDURE sp_priority_demo()
BEGIN
  -- 1. 最優先:錯誤碼 1062
  DECLARE EXIT HANDLER FOR 1062 SELECT 'Handler 1: MySQL 1062';

  -- 2. 次優先:SQLSTATE 23000 (含 1062)
  DECLARE EXIT HANDLER FOR SQLSTATE '23000' SELECT 'Handler 2: SQLSTATE 23000';

  -- 3. 最低:SQLEXCEPTION (含 23000)
  DECLARE EXIT HANDLER FOR SQLEXCEPTION SELECT 'Handler 3: SQLEXCEPTION';

  INSERT INTO article_tags (article_id, tag_id) VALUES (1, 1);  -- 首次成功
  INSERT INTO article_tags (article_id, tag_id) VALUES (1, 1);  -- 觸發 1062
END;

-- 執行結果:輸出 "Handler 1: MySQL 1062"

四、命名條件:消除魔術數字

-- 聲明
DECLARE duplicate_key CONDITION FOR 1062;
DECLARE fk_violation CONDITION FOR 1216;
DECLARE data_too_long CONDITION FOR SQLSTATE '22001';

-- 使用
DECLARE EXIT HANDLER FOR duplicate_key
BEGIN
  SET @ret = -1;
  SET @msg = '唯一鍵衝突';
END;

DECLARE EXIT HANDLER FOR fk_violation
  SET @ret = -2;

五、完整實戰範例:文章標籤關聯寫入

CREATE TABLE article_tags (
  article_id INT,
  tag_id INT,
  PRIMARY KEY (article_id, tag_id)
) ENGINE=InnoDB;

DELIMITER $$
CREATE PROCEDURE sp_add_article_tag(
  IN p_art_id INT,
  IN p_tag_id INT
)
BEGIN
  DECLARE EXIT HANDLER FOR 1062
    SELECT CONCAT('重複鍵: (', p_art_id, ',', p_tag_id, ')') AS msg;

  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    ROLLBACK;
    SELECT '系統異常,操作已回滾' AS msg;
  END;

  START TRANSACTION;
  INSERT INTO article_tags (article_id, tag_id) VALUES (p_art_id, p_tag_id);
  COMMIT;

  SELECT COUNT(*) AS tag_cnt FROM article_tags WHERE article_id = p_art_id;
END$$
DELIMITER ;

六、最佳實踐清單

  1. 按優先級聲明:具體錯誤碼/ SQLSTATE 寫在前,泛類 (SQLEXCEPTION) 兜底在後。
  2. 事務邊界保護:EXIT HANDLER 中必須 ROLLBACK,防止部分提交造成數據不一致。
  3. 錯誤碼標準化:定義業務錯誤碼表 (如 -1 重複、-2 系統錯),應用層統一映射 HTTP 狀態碼。
  4. 命名條件提升可讀性:杜絕裸數字 1062/1216 分散在代碼中。
  5. 游標/SELECT INTO 必捕獲 NOT FOUND:否則循環不會終止,導致無限循環。
  6. 避免 UNDO:MySQL 不支援,用 EXIT + ROLLBACK 替代。
  7. 測試覆蓋:單元測試需包含正常路徑、預期異常、非預期異常三類。

錯誤處理不是「寫上 HANDLER 就完事」,而是要構建「感知→記錄→轉換→回滾→上報」的完整鏈路,讓資料庫層成為系統穩定性的最後一道防線。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved