MySQL 存儲程序支援結構化異常處理:聲明條件 → 聲明處理器 → 捕獲執行,確保業務邏輯在錯誤發生時可控繼續或優雅退出。
DECLARE condition_name CONDITION FOR condition_type;
condition_type:
SQLSTATE [VALUE] sqlstate_value
| mysql_error_code
-- 方式一:SQLSTATE (標準 SQL 狀態碼) DECLARE duplicate_key CONDITION FOR SQLSTATE '23000'; -- 方式二:MySQL 錯誤碼 DECLARE duplicate_key CONDITION FOR 1062;
SQLSTATE '23000' 對應完整性約束違反 (主鍵衝突、唯一鍵衝突、外鍵約束等),1062 為 MySQL 具體錯誤碼「Duplicate entry」。
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 開頭 SQLSTATE (游標無數據等)
| SQLEXCEPTION -- 所有未被上述捕獲的錯誤
| mysql_error_code
-- 1. 捕獲具體 SQLSTATE DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @msg = 'Duplicate key'; -- 2. 捕獲具體錯誤碼 DECLARE CONTINUE HANDLER FOR 1062 SET @msg = 'Duplicate entry'; -- 3. 先聲明條件再捕獲 (推薦,可讀性強) DECLARE duplicate_key CONDITION FOR 1062; DECLARE CONTINUE HANDLER FOR duplicate_key SET @msg = 'Duplicate entry'; -- 4. 捕獲所有警告 DECLARE EXIT HANDLER FOR SQLWARNING SET @msg = 'Warning occurred'; -- 5. 捕獲 NOT FOUND (游標結束/SELECT 無結果) DECLARE EXIT HANDLER FOR NOT FOUND SET @msg = 'No data found'; -- 6. 捕獲所有異常 (兜底) DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @msg = 'Error occurred';
CREATE TABLE location (
location_id INT PRIMARY KEY,
location_name VARCHAR(50)
);
DELIMITER //
CREATE PROCEDURE insert_no_handler()
BEGIN
SET @x = 1;
INSERT INTO location VALUES (1, 'Beijing');
SET @x = 2;
INSERT INTO location VALUES (1, 'Wuxi'); -- 主鍵衝突
SET @x = 3;
END //
DELIMITER ;
CALL insert_no_handler();
SELECT @x; -- 結果: 2 (第二條 INSERT 失敗,默認 EXIT 退出)
DELIMITER //
CREATE PROCEDURE insert_with_continue()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @err = 1;
SET @x = 1;
INSERT INTO location VALUES (1, 'Beijing');
SET @x = 2;
INSERT INTO location VALUES (1, 'Wuxi'); -- 觸發處理器
SET @x = 3;
END //
DELIMITER ;
CALL insert_with_continue();
SELECT @x; -- 結果: 3 (繼續執行到結尾)
SELECT @err; -- 結果: 1
@var 用戶會話變量,連接級別,客戶端斷開自動釋放DECLARE var 局部變量,僅在 BEGIN...END 塊內有效| 業務需求 | 推薦類型 | 說明 |
|---|---|---|
| 記錄錯誤日誌,繼續處理後續記錄 | CONTINUE | 批量導入、數據清洗 |
| 關鍵業務失敗即停止,上層事務回滾 | EXIT | 轉賬、扣款等強一致性場景 |
| 游標遍歷結束標誌 | NOT FOUND | FETCH 循環結束條件 |
MySQL 異常處理雖不如 Java/Go 豐富,但掌握 CONDITION + HANDLER (CONTINUE/EXIT) + SQLEXCEPTION/SQLWARNING/NOT FOUND 核心組合,足以應對存儲過程中 95% 的錯誤控制場景。核心原則:具體錯誤具體捕獲,通用異常兜底記錄,關鍵業務用 EXIT 保護事務邊界。