首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 存儲過程異常處理實戰:DECLARE HANDLER 捕獲 SQLWARNING/NOT FOUND/SQLEXCEPTION

     編輯:MySQL 資料庫相關知識

前言

存儲過程執行時遇到錯誤預設會拋出異常中止。MySQL 提供 DECLARE ... HANDLER 機制,可捕獲 SQLWARNING、NOT FOUND、SQLEXCEPTION 三大類異常,實現優雅降級、返回錯誤碼而非拋出異常。

一、異常類型對照表

類型對應場景SQLSTATE 範例
SQLWARNING警告(如數據截斷、舊語法)01xxx
NOT FOUND游標無數據、SELECT ... INTO 空結果02000
SQLEXCEPTION所有錯誤(主鍵衝突、外鍵失敗等)其他

二、基本語法

DECLARE {CONTINUE | EXIT} HANDLER FOR {SQLWARNING | NOT FOUND | SQLEXCEPTION | SQLSTATE 'xxxxx'}
  statement;
  • CONTINUE:執行 handler 後繼續後續語句
  • EXIT:執行 handler 後退出當前 BEGIN...END 塊
  • FOR SQLWARNING, NOT FOUND, SQLEXCEPTION:捕獲所有類型(等同 Oracle WHEN OTHERS)
  • FOR SQLSTATE '23000':精準捕獲特定錯誤碼(如主鍵衝突)

三、實戰案例

案例 1:主鍵衝突返回錯誤碼而非拋出異常

CREATE PROCEDURE test_proc_ins1(
  IN i_id INT, IN i_name VARCHAR(100), OUT o_ret INT
)
BEGIN
  DECLARE EXIT HANDLER FOR SQLSTATE '23000' SET o_ret = -1;
  -- 也可寫成:DECLARE EXIT HANDLER FOR SQLWARNING, NOT FOUND, SQLEXCEPTION SET o_ret = -1;
  
  INSERT INTO testproc VALUES (i_id, i_name);
  INSERT INTO testproc VALUES (i_id, i_name);  -- 故意衝突
  SET o_ret = 1;
END;

Java 呼叫端可直接檢查 o_ret 而無需 try-catch 捕獲 SQLException。

案例 2:事務中遇錯誤自動回滾並記錄

DELIMITER //
CREATE PROCEDURE TEST()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND
  BEGIN
    ROLLBACK;
    INSERT INTO bb VALUES('error');
  END;
  
  START TRANSACTION;
  INSERT INTO aa VALUES (1);
  INSERT INTO aa VALUES (2);
  COMMIT;
END;
//
CALL TEST()//

四、最佳實踐建議

  1. 精準捕獲:優先用 SQLSTATE '23000' 針對性處理主鍵/唯一鍵衝突,避免誤吞其他嚴重錯誤
  2. 區分 CONTINUE/EXIT:需繼續執行用 CONTINUE;嚴重錯誤應 EXIT 並回滾
  3. 記錄錯誤上下文:Handler 內記錄 GET DIAGNOSTICS 或寫入審計表
  4. 避免濫用:業務邏輯錯誤應在代碼層驗證,而非依賴數據庫異常處理
  5. 測試覆蓋:單元測試必須覆蓋異常分支,確保 Handler 行為符合預期

五、MySQL 8.0 新特性

  • 支援 GET STACKED DIAGNOSTICS 獲取更豐富的錯誤堆疊資訊
  • 錯誤碼體系更完善,建議遷移時重新審視異常處理邏輯
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved