萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL 存儲過程異常處理:HANDLER 機制深度解析

從 EXIT 到 CONTINUE,構建健壯的資料庫錯誤防線

存儲過程中異常處理是保證數據一致性、簡化應用層錯誤碼的關鍵。MySQL 提供 DECLARE ... HANDLER 機制,支援按錯誤碼、SQLSTATE、命名條件三種方式捕獲,配合 EXIT/CONTINUE 兩種行為模式,靈活應對各類異常場景。

HANDLER 語法全景

DECLARE {EXIT | CONTINUE} HANDLER
    FOR {error_code | SQLSTATE 'value' | condition_name}
    statement;

兩大行為模式對比

模式執行後流程典型用途
EXIT離開當前 BEGIN ... END 塊記錄錯誤日誌、回滾事務、設置輸出狀態碼
CONTINUE繼續執行緊隨其後的語句標記錯誤旗標、嘗試替代邏輯、收集多錯誤信息

實戰場景 1:外鍵衝突記錄日誌(EXIT)

-- 建表
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;  -- 記錄落地,主過程靜默結束

實戰場景 2:主鍵衝突不中斷批次(CONTINUE)

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 決定是否重試。

實戰場景 3:自定義條件 + 事務回滾

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 ;

游標專用異常:NOT FOUND (02000)

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 ;

進階技巧:在 HANDLER 內執行多條語句

用 BEGIN ... END 包裹:

DECLARE CONTINUE HANDLER FOR SQLSTATE '02000'
BEGIN
    SET @flag = 1;
    INSERT INTO audit_log VALUES ('cursor exhausted', NOW());
    -- 甚至可以再開事務、調用其他過程
END;

常見 SQLSTATE 速查

SQLSTATE含義典型觸發
02000NOT FOUND游標無數據、SELECT ... INTO 無行
23000完整性約束違規主鍵/唯一/外鍵衝突
42000語法/權限錯誤SQL 語法錯、權限不足
HY000通用錯誤其他未分類錯誤

最佳實踐原則

  1. 具體優於通用:優先捕獲具體錯誤碼/狀態,避免 SQLEXCEPTION 吞噬預期外錯誤。
  2. EXIT 守住事務邊界:事務塊外層用 EXIT ... ROLLBACK,內層業務用 CONTINUE 記錄細節。
  3. 命名條件提升可讀性:DECLARE deadlock CONDITION FOR SQLSTATE '40001';
  4. 避免在 HANDLER 中再次觸發同類異常,否則陷入無限遞歸。
  5. MySQL 8.0+ 考慮用 GET DIAGNOSTICS 獲取詳細錯誤信息。

總結

掌握 HANDLER 三要素——捕獲條件、行為模式、處理語句,即可構建「不拋異常到應用層、數據不壞、日誌全留」的健壯存儲過程體系。

copyright © 萬盛學電腦網 all rights reserved