| 類型 | 行為 | 適用場景 |
| CONTINUE | 執行處理動作後,**繼續**執行後續語句 | 預期內錯誤(如重複鍵),記錄並跳過 |
| EXIT | 執行處理動作後,**退出**當前 BEGIN...END 塊 | 嚴重錯誤,需終止流程 |
| UNDO | 執行處理動作後,**回滾**當前事務並退出 | 需保證原子性的業務邏輯 |
完整示例:員工管理存儲過程
DELIMITER $$
CREATE PROCEDURE `sp_add_employee`(
IN p_first_name VARCHAR(30),
IN p_last_name VARCHAR(30),
IN p_city VARCHAR(30),
IN p_description VARCHAR(30),
OUT p_sqlcode INT,
OUT p_status_msg VARCHAR(100)
)
BEGIN
/* 1. 聲明業務相關錯誤條件 */
DECLARE duplicate_key CONDITION FOR 1062; -- ER_DUP_ENTRY
DECLARE foreign_key_violated CONDITION FOR 1216; -- ER_NO_REFERENCED_ROW_2
/* 2. 聲明變量與游標 */
DECLARE v_manager_id INT;
DECLARE cur_mgr CURSOR FOR
SELECT id FROM employee
WHERE first_name = p_first_name AND last_name = p_last_name;
/* 3. 聲明異常處理器 */
DECLARE CONTINUE HANDLER FOR duplicate_key
BEGIN
SET p_sqlcode = 1062;
SET p_status_msg = 'Duplicate key error';
END;
DECLARE CONTINUE HANDLER FOR foreign_key_violated
BEGIN
SET p_sqlcode = 1216;
SET p_status_msg = 'Foreign key violated';
END;
DECLARE CONTINUE HANDLER FOR NOT FOUND
BEGIN
SET p_sqlcode = 1329;
SET p_status_msg = 'No record found';
END;
/* 4. 業務邏輯 */
SET p_sqlcode = 0;
OPEN cur_mgr;
FETCH cur_mgr INTO v_manager_id;
IF p_sqlcode <> 0 THEN
SET p_status_msg = CONCAT(p_status_msg, ' when fetching manager');
ELSE
INSERT INTO employee (first_name, manager_id, city, description)
VALUES (p_first_name, v_manager_id, p_city, p_description);
IF p_sqlcode <> 0 THEN
SET p_status_msg = CONCAT(p_status_msg, ' when inserting employee');
END IF;
END IF;
CLOSE cur_mgr;
END$$
DELIMITER ;
測試調用
SET @code = 0, @msg = '';
CALL sp_add_employee('Jason', 'Martin', 'New City', 'Desc', @code, @msg);
SELECT @code AS sqlcode, @msg AS message;
MySQL 常見錯誤碼速查
| 錯誤碼 | SQLSTATE | 常量名 | 含義 |
| 1062 | 23000 | ER_DUP_ENTRY | 重複鍵值 |
| 1048 | 23000 | ER_BAD_NULL_ERROR | 非空列插入 NULL |
| 1216 | 23000 | ER_NO_REFERENCED_ROW_2 | 外鍵約束失敗 |
| 1217 | 23000 | ER_ROW_IS_REFERENCED_2 | 被引用行無法刪除 |
| 1329 | 02000 | ER_NO_DATA | 游標無數據 / NOT FOUND |
| 1205 | HY000 | ER_LOCK_WAIT_TIMEOUT | 鎖等待超時 |
| 1213 | 40001 | ER_LOCK_DEADLOCK | 死鎖 |
進階技巧
1. GET DIAGNOSTICS 獲取詳細信息
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
@errno = MYSQL_ERRNO,
@state = RETURNED_SQLSTATE,
@msg = MESSAGE_TEXT;
SET p_status_msg = CONCAT('Error ', @errno, ' (', @state, '): ', @msg);
END;
2. 嵌套塊的異常傳播
內層塊無處理器時,異常向外層傳播;內層有 CONTINUE 處理器執行後,外層不再感知該異常。
3. 事務邊界與異常
- 隱式事務:每條語句自動提交(autocommit=1)
- 顯式事務:
START TRANSACTION + COMMIT/ROLLBACK
- UNDO HANDLER 自動回滾到事務起始點
最佳實踐
- 針對業務關鍵錯誤碼(1062、1216、1329)聲明專用條件
- 使用 CONTINUE 處理預期錯誤,EXIT/UNDO 處理嚴重錯誤
- 輸出參數返回統一錯誤碼 + 人類可讀消息,便於應用層處理
- 處理器中務必
DEALLOCATE PREPARE 清理動態 SQL 資源
- 避免在處理器中執行複雜邏輯,保持輕量
掌握 DECLARE ... HANDLER 機制,將錯誤處理從應用層下沉到存儲過程層,能顯著提升數據庫端的健壯性與可維護性。
- 上一篇文章: MySQL 存儲過程動態 SQL 實戰:PREPARE/EXECUTE 實現運行時構建查詢
- 下一篇文章: MySQL 存儲過程 WHILE 循環實戰:標籤控制流與條件跳過
Copyright ©
程式碼之家 All Rights Reserved