預存程序執行過程中可能遇到:重複鍵衝突、外鍵違反、資料截斷、除零錯誤、死鎖等。若無處理機制,程序**中止並拋出錯誤**,呼叫端難以優雅處理。條件處理器允許**捕獲特定錯誤並執行替代邏輯**(重試、記錄、跳過、回滾)。
DECLARE condition_name CONDITION FOR condition_value;
condition_value:
SQLSTATE [VALUE] sqlstate_value -- 標準 SQLSTATE 代碼(如 '23000')
| mysql_error_code -- MySQL 錯誤碼(如 1062)
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 記錄
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 | 類別 | 典型錯誤 | MySQL 錯誤碼 |
|---|---|---|---|
| 00000 | 成功 | 無錯誤 | 0 |
| 01000 | 警告 | 警告 | 1000+ |
| 02000 | 未找到 | 游標無資料、SELECT INTO 無結果 | 1329 |
| 23000 | 完整性違反 | 重複鍵、外鍵失敗、非空違反 | 1062, 1452, 1048 |
| 40001 | 序列化失敗 | 死鎖 | 1213 |
| 42000 | 語法/存取 | 語法錯誤、權限不足 | 1064, 1142 |
| HY000 | 一般錯誤 | 表滿、記憶體不足、未知錯誤 | 1114, 1030 |
SQLEXCEPTION 兜底