MySQL 儲存過程透過 DECLARE ... HANDLER 實現結構化異常處理,支援錯誤碼、SQLSTATE、命名條件、警告/未找到/異常三大類別,以及 CONTINUE/EXIT/UNDO 三種動作。本文系統解析語法、語義與實戰模式。
DECLARE handler_action HANDLER
FOR condition_value [, condition_value] ...
statement
handler_action: CONTINUE | EXIT | UNDO
condition_value:
mysql_error_code
| SQLSTATE [VALUE] sqlstate_value
| condition_name
| SQLWARNING
| NOT FOUND
| SQLEXCEPTION
| 類別 | condition_value | 說明 | 範例 |
|---|---|---|---|
| 精確匹配 | mysql_error_code | MySQL 專屬錯誤碼 | 1062 (Duplicate entry) |
| SQLSTATE [VALUE] sqlstate_value | ANSI/ODBC 標準 5 碼 | '23000' (完整性約束違規) | |
| condition_name | 自定義命名條件 | DECLARE dup_key CONDITION FOR 1062 | |
| 類別匹配 | SQLWARNING | SQLSTATE 以 '01' 開頭 | 警告,如截斷 |
| NOT FOUND | SQLSTATE 以 '02' 開頭 | 游標無資料 | |
| SQLEXCEPTION | SQLSTATE 非 '00'/'01'/'02' | 真正錯誤 |
SQLWARNING、NOT FOUND:**忽略繼續執行**(CONTINUE)SQLEXCEPTION:**立即終止過程**(EXIT)CONTINUE:執行 statement 後,**繼續**下一條指令EXIT:執行 statement 後,**離開**當前 BEGIN...END 區塊UNDO:執行 statement 後,**回滾**事務(**暫不支援**)DECLARE foreign_key_error CONDITION FOR 1216;
-- 或標準 SQLSTATE
DECLARE foreign_key_error CONDITION FOR SQLSTATE '23000';
DECLARE CONTINUE HANDLER FOR foreign_key_error
SET @err_msg = 'Foreign key violation';
CREATE PROCEDURE sp_add_location (
IN in_location VARCHAR(30), IN in_address1 VARCHAR(30),
IN in_address2 VARCHAR(30), IN in_zipcode VARCHAR(10),
OUT out_status VARCHAR(30)
)
BEGIN
DECLARE CONTINUE HANDLER FOR 1062 -- ER_DUP_ENTRY
SET out_status = 'Duplicate Entry';
SET out_status = 'OK';
INSERT INTO locations (location, address1, address2, zipcode)
VALUES (in_location, in_address1, in_address2, in_zipcode);
END;
DECLARE done INT DEFAULT FALSE;
DECLARE cur CURSOR FOR SELECT id FROM t;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO v_id;
IF done THEN LEAVE read_loop; END IF;
-- 處理 v_id
END LOOP;
CLOSE cur;
SQLEXCEPTION 記錄錯誤上下文、NOT FOUND 控制游標循環CONTINUE,不可繼續用 EXIT結構化異常處理,讓儲存過程具備生產級健壯性。