存儲過程執行時遇到錯誤預設會拋出異常中止。MySQL 提供 DECLARE ... HANDLER 機制,可捕獲 SQLWARNING、NOT FOUND、SQLEXCEPTION 三大類異常,實現優雅降級、返回錯誤碼而非拋出異常。
| 類型 | 對應場景 | SQLSTATE 範例 |
|---|---|---|
| SQLWARNING | 警告(如數據截斷、舊語法) | 01xxx |
| NOT FOUND | 游標無數據、SELECT ... INTO 空結果 | 02000 |
| SQLEXCEPTION | 所有錯誤(主鍵衝突、外鍵失敗等) | 其他 |
DECLARE {CONTINUE | EXIT} HANDLER FOR {SQLWARNING | NOT FOUND | SQLEXCEPTION | SQLSTATE 'xxxxx'}
statement;
CONTINUE:執行 handler 後繼續後續語句EXIT:執行 handler 後退出當前 BEGIN...END 塊FOR SQLWARNING, NOT FOUND, SQLEXCEPTION:捕獲所有類型(等同 Oracle WHEN OTHERS)FOR SQLSTATE '23000':精準捕獲特定錯誤碼(如主鍵衝突)CREATE PROCEDURE test_proc_ins1( IN i_id INT, IN i_name VARCHAR(100), OUT o_ret INT ) BEGIN DECLARE EXIT HANDLER FOR SQLSTATE '23000' SET o_ret = -1; -- 也可寫成:DECLARE EXIT HANDLER FOR SQLWARNING, NOT FOUND, SQLEXCEPTION SET o_ret = -1; INSERT INTO testproc VALUES (i_id, i_name); INSERT INTO testproc VALUES (i_id, i_name); -- 故意衝突 SET o_ret = 1; END;
Java 呼叫端可直接檢查 o_ret 而無需 try-catch 捕獲 SQLException。
DELIMITER //
CREATE PROCEDURE TEST()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND
BEGIN
ROLLBACK;
INSERT INTO bb VALUES('error');
END;
START TRANSACTION;
INSERT INTO aa VALUES (1);
INSERT INTO aa VALUES (2);
COMMIT;
END;
//
CALL TEST()//
SQLSTATE '23000' 針對性處理主鍵/唯一鍵衝突,避免誤吞其他嚴重錯誤GET DIAGNOSTICS 或寫入審計表GET STACKED DIAGNOSTICS 獲取更豐富的錯誤堆疊資訊