MySQL 存儲過程通過 DECLARE ... HANDLER 捕獲運行時錯誤,實現「遇錯不中斷」或「優雅退出」的業務邏輯。本文系統梳理語法結構、條件值分類、SQLSTATE 與錯誤碼映射,並通過三個完整案例演示 EXIT、CONTINUE、SQLWARNING 三種處理器的行為差異。
DECLARE handler_type HANDLER FOR condition_value[,...] statement handler_type: CONTINUE | EXIT | UNDO -- UNDO 暫不支援 condition_value: SQLSTATE [VALUE] sqlstate_value -- ANSI/ODBC 標準 5 碼 | condition_name -- 自定義條件名 | SQLWARNING -- 所有 01 開頭警告 | NOT FOUND -- 02 開頭 / 游標無數據 | SQLEXCEPTION -- 除上述外所有錯誤 | mysql_error_code -- MySQL 原生數字錯誤碼
01xxx 類警告(如截斷、舊密碼)。02xxx 類,含游標讀完、SELECT ... INTO 無行。查閱完整映射:https://dev.mysql.com/doc/refman/5.0/en/error-messages-server.html 或安裝目錄 share/mysql/errmsg.txt。
CREATE TABLE t (s1 INT PRIMARY KEY); DELIMITER // CREATE PROCEDURE handlerdemo() BEGIN DECLARE EXIT HANDLER FOR SQLSTATE '23000' BEGIN END; -- 23000 = 完整性約束違規 SET @x = 1; INSERT INTO t VALUES (1); SET @x = 2; INSERT INTO t VALUES (1); -- 觸發 1062 / 23000,進入 HANDLER,結束過程 SET @x = 3; -- 不會執行 END// DELIMITER ; CALL handlerdemo(); SELECT @x; -- 結果 @x = 2
行為:第二次 INSERT 報錯 → 進入 EXIT 處理器 → 直接離開 BEGIN...END 塊,後續語句不執行。
DROP PROCEDURE IF EXISTS handlerdemo; DELIMITER // CREATE PROCEDURE handlerdemo() BEGIN DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' BEGIN END; SET @x = 1; INSERT INTO t VALUES (1); SET @x = 2; INSERT INTO t VALUES (1); -- 報錯但被捕獲,繼續 SET @x = 3; -- 正常執行 END// DELIMITER ; CALL handlerdemo(); SELECT @x; -- 結果 @x = 3
行為:錯誤被「吞掉」,流程無感知地繼續,最終 @x 為 3。
ALTER TABLE t ADD s2 INT NOT NULL; -- 無默認值,插入時會產生 1364 警告/錯誤
DELIMITER //
CREATE PROCEDURE handlerdemo()
BEGIN
DECLARE CONTINUE HANDLER FOR 1062 BEGIN END; -- 主鍵衝突忽略
DECLARE CONTINUE HANDLER FOR SQLWARNING -- 任何警告
BEGIN UPDATE t SET s2 = 2; END; -- 將 s2 設為 2
DECLARE CONTINUE HANDLER FOR 1364 -- Field doesn't have default value
BEGIN INSERT INTO t(s1,s2) VALUES (1,3); END; -- 改用顯式插入
SET @x = 1; INSERT INTO t(s1) VALUES (1);
SET @x = 2; INSERT INTO t(s1) VALUES (1); -- 觸發 1062
SET @x = 3;
END//
DELIMITER ;
CALL handlerdemo();
SELECT * FROM t; -- 僅一行 (1,3)
SELECT @x; -- 3
解析:首次插入觸發 1364 → 進入第三個 HANDLER 插入 (1,3);第二次插入觸發 1062 → 進入第一個 HANDLER 靜默忽略;最終 @x=3,數據唯一且完整。
SQLEXCEPTION 吞噬真實 Bug。GET DIAGNOSTICS:MySQL 5.6+ 可在 HANDLER 內獲取詳細錯誤資訊,便於審計。靈活運用異常處理器,能讓存儲過程在「脏數據、併發衝突、邊界條件」下依然保持健壯,是編寫企業級存儲邏輯的必備技能。