存儲過程中異常處理是保證數據一致性、簡化應用層錯誤碼的關鍵。MySQL 提供 DECLARE ... HANDLER 機制,支援按錯誤碼、SQLSTATE、命名條件三種方式捕獲,配合 EXIT/CONTINUE 兩種行為模式,靈活應對各類異常場景。
DECLARE {EXIT | CONTINUE} HANDLER
FOR {error_code | SQLSTATE 'value' | condition_name}
statement;
| 模式 | 執行後流程 | 典型用途 |
|---|---|---|
EXIT | 離開當前 BEGIN ... END 塊 | 記錄錯誤日誌、回滾事務、設置輸出狀態碼 |
CONTINUE | 繼續執行緊隨其後的語句 | 標記錯誤旗標、嘗試替代邏輯、收集多錯誤信息 |
-- 建表
CREATE TABLE t2 (s1 INT PRIMARY KEY) ENGINE=InnoDB;
CREATE TABLE t3 (s1 INT, KEY(s1), FOREIGN KEY(s1) REFERENCES t2(s1)) ENGINE=InnoDB;
CREATE TABLE error_log (msg VARCHAR(200));
-- 過程
DELIMITER //
CREATE PROCEDURE p_fk_safe(IN val INT)
BEGIN
DECLARE EXIT HANDLER FOR 1452 -- ER_NO_REFERENCED_ROW_2
BEGIN
INSERT INTO error_log VALUES (CONCAT('FK violation: ', val, ' @ ', NOW()));
ROLLBACK; -- 若在事務中
END;
INSERT INTO t3 VALUES (val);
END //
DELIMITER ;
-- 測試
CALL p_fk_safe(999); -- 999 不在 t2 中
SELECT * FROM error_log; -- 記錄落地,主過程靜默結束
CREATE TABLE t4 (s1 INT PRIMARY KEY);
DELIMITER //
CREATE PROCEDURE p_batch_insert()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @dup = 1;
SET @x = 1; INSERT INTO t4 VALUES (1);
SET @x = 2; INSERT INTO t4 VALUES (1); -- 重複鍵
SET @x = 3; INSERT INTO t4 VALUES (2);
SELECT @x, @dup; -- @x=3, @dup=1
END //
DELIMITER ;
CALL p_batch_insert();
💡 關鍵點:CONTINUE 讓批次「盡力而為」,應用層最後檢查 @dup 決定是否重試。
DELIMITER //
CREATE PROCEDURE p_tx_guard()
BEGIN
DECLARE my_violation CONDITION FOR SQLSTATE '23000';
DECLARE EXIT HANDLER FOR my_violation ROLLBACK;
START TRANSACTION;
INSERT INTO t2 VALUES (1);
INSERT INTO t2 VALUES (1); -- 觸發主鍵衝突
COMMIT; -- 不會執行
END //
DELIMITER ;
DELIMITER //
CREATE PROCEDURE p_cursor_safe(OUT last_val INT)
BEGIN
DECLARE v INT;
DECLARE done INT DEFAULT 0;
DECLARE cur CURSOR FOR SELECT s1 FROM t;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
REPEAT
FETCH cur INTO v;
IF NOT done THEN SET last_val = v; END IF;
UNTIL done END REPEAT;
CLOSE cur;
END //
DELIMITER ;
用 BEGIN ... END 包裹:
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000'
BEGIN
SET @flag = 1;
INSERT INTO audit_log VALUES ('cursor exhausted', NOW());
-- 甚至可以再開事務、調用其他過程
END;
| SQLSTATE | 含義 | 典型觸發 |
|---|---|---|
| 02000 | NOT FOUND | 游標無數據、SELECT ... INTO 無行 |
| 23000 | 完整性約束違規 | 主鍵/唯一/外鍵衝突 |
| 42000 | 語法/權限錯誤 | SQL 語法錯、權限不足 |
| HY000 | 通用錯誤 | 其他未分類錯誤 |
SQLEXCEPTION 吞噬預期外錯誤。EXIT ... ROLLBACK,內層業務用 CONTINUE 記錄細節。DECLARE deadlock CONDITION FOR SQLSTATE '40001';掌握 HANDLER 三要素——捕獲條件、行為模式、處理語句,即可構建「不拋異常到應用層、數據不壞、日誌全留」的健壯存儲過程體系。