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

MySQL 預存程序條件處理與錯誤捕獲:DECLARE CONDITION/HANDLER 完整指南

     編輯:MySQL 綜合教學

為什麼需要條件處理?

預存程序執行過程中可能遇到:重複鍵衝突、外鍵違反、資料截斷、除零錯誤、死鎖等。若無處理機制,程序**中止並拋出錯誤**,呼叫端難以優雅處理。條件處理器允許**捕獲特定錯誤並執行替代邏輯**(重試、記錄、跳過、回滾)。

語法核心

1. 條件宣告


DECLARE condition_name CONDITION FOR condition_value;

condition_value:
    SQLSTATE [VALUE] sqlstate_value   -- 標準 SQLSTATE 代碼(如 '23000')
  | mysql_error_code                  -- MySQL 錯誤碼(如 1062)

2. 處理器宣告


DECLARE handler_type HANDLER FOR condition_value [, ...] statement;

handler_type:
    CONTINUE   -- 執行 statement 後繼續執行後續語句
  | EXIT       -- 執行 statement 後離開當前 BEGIN...END 區塊
  | UNDO       -- (MySQL 暫不支援) 回滾並離開

condition_value:
    SQLSTATE [VALUE] sqlstate_value
  | condition_name
  | SQLWARNING      -- 所有 01 開頭 SQLSTATE
  | NOT FOUND       -- 02 開頭(游標無資料、SELECT ... INTO 無結果)
  | SQLEXCEPTION    -- 除上述外所有錯誤
  | mysql_error_code

實戰範例:處理重複鍵錯誤


DELIMITER //

CREATE PROCEDURE actor_insert_demo()
BEGIN
    -- 宣告條件:重複鍵錯誤 (1062 / 23000)
    DECLARE duplicate_key CONDITION FOR 1062;
    DECLARE duplicate_key CONDITION FOR SQLSTATE '23000';
    
    -- 宣告處理器:遇到重複鍵,記錄日誌並繼續
    DECLARE CONTINUE HANDLER FOR duplicate_key
    BEGIN
        INSERT INTO error_log (err_code, err_msg, created_at)
        VALUES (1062, 'Duplicate key ignored', NOW());
    END;
    
    -- 宣告處理器:其他 SQL 錯誤,記錄並退出
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        GET DIAGNOSTICS CONDITION 1
            @errno = MYSQL_ERRNO, @sqlstate = RETURNED_SQLSTATE, @msg = MESSAGE_TEXT;
        INSERT INTO error_log (err_code, err_msg, created_at)
        VALUES (@errno, @msg, NOW());
        ROLLBACK;
    END;
    
    START TRANSACTION;
    
    INSERT INTO actor (id, name) VALUES (201, 'Test A');  -- 假設 201 已存在
    INSERT INTO actor (id, name) VALUES (202, 'Test B');  -- 正常插入
    INSERT INTO actor (id, name) VALUES (203, 'Test C');  -- 正常插入
    
    COMMIT;
END //

DELIMITER ;

執行結果分析


CALL actor_insert_demo();

-- 結果:
-- 1. 第一條 INSERT 觸發 1062 錯誤
-- 2. CONTINUE HANDLER 執行:寫入 error_log
-- 3. 程序**繼續執行**後續 INSERT (202, 203 成功)
-- 4. 事務提交(202, 203 入庫)
-- 5. error_log 有一條 1062 記錄

進階:GET DIAGNOSTICS 取得錯誤詳情


DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
    GET DIAGNOSTICS CONDITION 1
        @errno = MYSQL_ERRNO,           -- MySQL 錯誤碼
        @sqlstate = RETURNED_SQLSTATE,  -- SQLSTATE
        @msg = MESSAGE_TEXT;            -- 錯誤訊息
    
    INSERT INTO proc_error_log (proc_name, err_code, sqlstate, err_msg, created_at)
    VALUES ('actor_insert_demo', @errno, @sqlstate, @msg, NOW());
    
    RESIGNAL;  -- 重新拋出錯誤讓呼叫端感知(可選)
END;

常見 SQLSTATE 代碼速查

SQLSTATE類別典型錯誤MySQL 錯誤碼
00000成功無錯誤0
01000警告警告1000+
02000未找到游標無資料、SELECT INTO 無結果1329
23000完整性違反重複鍵、外鍵失敗、非空違反1062, 1452, 1048
40001序列化失敗死鎖1213
42000語法/存取語法錯誤、權限不足1064, 1142
HY000一般錯誤表滿、記憶體不足、未知錯誤1114, 1030

最佳實踐原則

  1. 具體優於通用:優先捕獲具體錯誤碼 (1062),最後才用 SQLEXCEPTION 兜底
  2. CONTINUE vs EXIT:可恢復錯誤用 CONTINUE,不可恢復用 EXIT + ROLLBACK
  3. 記錄完整上下文:錯誤碼、SQLSTATE、訊息、時間、呼叫參數、堆疊
  4. 避免在處理器中執行複雜邏輯:僅做記錄、設定旗標、簡單補償
  5. 測試所有錯誤路徑:單元測試覆蓋每個 HANDLER 分支
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved