首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 錯誤處理機制詳解:DECLARE HANDLER 實戰範例

     編輯:MySQL 資料庫相關知識

MySQL 儲存程序錯誤處理全攻略

在編寫儲存程序、觸發器或複雜事務時,優雅地處理錯誤至關重要。MySQL 提供了 DECLARE HANDLER 機制,可針對特定錯誤碼、SQLSTATE 或條件類型定義處理邏輯。本文詳細解析各類處理器語法與實戰模式。

一、處理器類型與語法

DECLARE {CONTINUE | EXIT} HANDLER FOR condition_value
statement;
  • CONTINUE:執行處理語句後,繼續執行當前程序塊的後續語句。
  • EXIT:執行處理語句後,退出當前 BEGIN...END 程序塊(或整個儲存程序)。

二、條件值(condition_value)三種形式

形式範例適用場景
MySQL 錯誤碼1062 (重複鍵)、1329 (游標無數據)針對特定 MySQL 原生錯誤
SQLSTATE 代碼'23000' (完整性約束違規)、'02000' (無數據)標準 SQL 狀態,跨資料庫可移植
命名條件SQLEXCEPTION、SQLWARNING、NOT FOUND涵蓋一類錯誤的通用處理

三、核心命名條件詳解

  • SQLEXCEPTION:涵蓋所有錯誤(除 NOT FOUND 外),如語法錯誤、約束違規、權限不足等。
  • SQLWARNING:非致命警告(如數據截斷、舊語法棄用)。
  • NOT FOUND:SELECT ... INTO、游標 FETCH 未返回行時觸發(SQLSTATE '02000')。

四、實戰範例集錦

1. 通用異常捕獲:記錄錯誤並繼續

DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SET l_error = 1;

適用於批量處理中,單條失敗不影響整體流程。

2. 嚴重錯誤:回滾並退出

DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
    ROLLBACK;
    SELECT 'Error occurred – terminating' AS msg;
END;

事務場景必備,確保數據一致性。

3. 重複鍵錯誤(1062 / 23000)專用處理

-- 方式一:MySQL 錯誤碼
DECLARE CONTINUE HANDLER FOR 1062
SELECT 'Duplicate key in index' AS msg;

-- 方式二:SQLSTATE(推薦,標準化)
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000'
SELECT 'Duplicate key in index' AS msg;

4. 游標/查詢無結果處理

-- 命名條件
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET l_done = 1;

-- 等價 SQLSTATE
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000'
SET l_done = 1;

-- 等價 MySQL 錯誤碼 1329
DECLARE CONTINUE HANDLER FOR 1329
SET l_done = 1;

常用於游標循環結束判斷。

五、進階技巧與最佳實踐

  1. 優先使用 SQLSTATE:避免 MySQL 版本升級導致錯誤碼變更。
  2. 處理器作用域:僅在聲明它的 BEGIN...END 塊內有效。巢狀塊可覆蓋外層處理器。
  3. 多處理器優先級:SQLSTATE > MySQL 錯誤碼 > 命名條件。精確匹配優先。
  4. 訪問錯誤資訊(MySQL 5.6+):在處理器內可用 GET DIAGNOSTICS 獲取詳細錯誤碼、訊息等。
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
    BEGIN
        GET DIAGNOSTICS CONDITION 1
            @errno = MYSQL_ERRNO, @msg = MESSAGE_TEXT;
        INSERT INTO error_log (errno, msg) VALUES (@errno, @msg);
    END;
    
  5. 避免在處理器中執行耗時操作:如發送郵件、外部 API 調用,應記錄後由異步任務處理。

六、完整儲存程序範例

DELIMITER //
CREATE PROCEDURE transfer_funds(
    IN from_acct INT, IN to_acct INT, IN amount DECIMAL(10,2)
)
BEGIN
    DECLARE l_error TINYINT DEFAULT 0;
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET l_error = 1;
    DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET l_error = 2; -- 重複鍵等

    START TRANSACTION;
    UPDATE accounts SET balance = balance - amount WHERE id = from_acct;
    UPDATE accounts SET balance = balance + amount WHERE id = to_acct;
    INSERT INTO transfer_log (from_acct, to_acct, amount) VALUES (from_acct, to_acct, amount);

    IF l_error = 1 THEN
        ROLLBACK;
        SELECT 'System error, rolled back' AS result;
    ELSEIF l_error = 2 THEN
        ROLLBACK;
        SELECT 'Constraint violation, rolled back' AS result;
    ELSE
        COMMIT;
        SELECT 'Success' AS result;
    END IF;
END//
DELIMITER ;
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved