MySQL 透過 DECLARE ... HANDLER 在預存程序中處理錯誤與警告。
DECLARE handler_type HANDLER FOR condition_value[,...] statement
handler_type: CONTINUE | EXIT | UNDO (暫不支援)
condition_value:
SQLSTATE [VALUE] sqlstate_value
| condition_name
| SQLWARNING -- 01 開頭錯誤代碼
| NOT FOUND -- 02 開頭 / 游標結束
| SQLEXCEPTION -- 除上述外所有錯誤
| MySQL_error_code
完整列表見安裝目錄 share/mysql/errmsg.txt。非所有 MySQL 錯誤碼皆映射至 SQLSTATE。
CREATE TABLE t (s1 INT, PRIMARY KEY (s1));
DELIMITER //
CREATE PROCEDURE handlerdemo()
BEGIN
DECLARE EXIT HANDLER FOR SQLSTATE '23000' BEGIN END; -- 重複鍵退出
SET @x = 1;
INSERT INTO t VALUES (1);
SET @x = 2;
INSERT INTO t VALUES (1); -- 這裡報錯,退出
SET @x = 3;
END//
DELIMITER ;
CALL handlerdemo(); SELECT @x; -- 結果 @x=2 (停在第二次 INSERT 前)
CREATE PROCEDURE handlerdemo()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' BEGIN END;
SET @x = 1;
INSERT INTO t VALUES (1);
SET @x = 2;
INSERT INTO t VALUES (1); -- 錯誤但繼續
SET @x = 3;
END;
CALL handlerdemo(); SELECT @x; -- 結果 @x=3 (執行完畢)
SQLSTATE '23000' 可替換為 MySQL 錯誤碼 1062 (Duplicate entry)。
ALTER TABLE t ADD s2 INT NOT NULL; -- 無預設值,INSERT 會警告/錯誤 1364
CREATE PROCEDURE handlerdemo()
BEGIN
DECLARE CONTINUE HANDLER FOR 1062 BEGIN END; -- 重複鍵忽略
DECLARE CONTINUE HANDLER FOR SQLWARNING -- 警告處理
BEGIN UPDATE t SET s2 = 2; END;
DECLARE CONTINUE HANDLER FOR 1364 -- 欄位無預設值錯誤
BEGIN INSERT INTO t(s1,s2) VALUES (1,3); END;
SET @x = 1;
INSERT INTO t(s1) VALUES (1); -- 觸發 1364,插入 (1,3)
SET @x = 2;
INSERT INTO t(s1) VALUES (1); -- 觸發 1062,忽略
SET @x = 3;
END;
CALL handlerdemo();
SELECT * FROM t; -- 結果: (1,3) 只有一行
SELECT @x; -- @x=3
| Handler Type | 行為 |
|---|---|
| EXIT | 發生條件時離開當前 BEGIN...END 區塊 |
| CONTINUE | 發生條件時繼續執行下一條語句 |
善用 HANDLER 可建立健壯的預存程序,避免單一錯誤導致整個流程中斷。