MySQL 存儲過程(Stored Procedure)是預編譯並存儲在數據庫中的一組 SQL 語句集合,可通過單次調用執行復雜邏輯(如多表查詢、事務處理、批量操作),核心優勢是複用性強、減少網絡傳輸、提升性能,適合封裝複雜業務邏輯。

與自定義函數(UDF)相比,存儲過程支持事務、寫操作(INSERT/UPDATE/DELETE)、返回多個結果集(通過參數、結果集、臨時表),是 MySQL 中處理複雜流程的核心工具。

DELIMITER 新結束符; -- 臨時修改結束符(避免與 SQL 內部 ; 衝突)
CREATE PROCEDURE [IF NOT EXISTS] 存儲過程名(
    IN param1 數據類型 [DEFAULT 默認值],  -- 輸入參數(默認)
    OUT param2 數據類型,                 -- 輸出參數(外部接收)
    INOUT param3 數據類型                -- 輸入輸出參數
)
[特性選項] -- 優化性能+告知 MySQL 行為
COMMENT 'string' -- 存儲過程的註釋
LANGUAGE SQL -- 儲存過程體是 SQL 語句
[NOT] DETERMINISTIC -- 是否輸入相同則輸出相同
{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
SQL SECURITY { DEFINER | INVOKER } -- 誰能執行存儲過程{ 定義者 | 調用者 }
BEGIN
    -- 1. 聲明局部變量(僅代碼塊內有效)
    DECLARE 局部變量名 數據類型 [DEFAULT 默認值];
    
    -- 2. 異常處理(可選,核心業務必加)
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK; -- 事務回滾
        SET param2 = '執行失敗'; -- 給 OUT 參數賦值
    END;

    -- 3. 核心邏輯(支持事務、循環、條件判斷等)
    START TRANSACTION; -- 開啓事務(多步寫操作必加)
    -- SQL 邏輯(INSERT/UPDATE/SELECT/循環等)
    COMMIT; -- 提交事務

    -- 4. 給 OUT/INOUT 參數賦值(必須)
    SET param2 = '執行成功';
    SET param3 = param3 + 10;
END 新結束符;
DELIMITER ; -- 恢復默認結束符 ;

存儲過程管理

-- 調用存儲過程(OUT/INOUT 參數需用 @ 用户變量接收)
CALL 存儲過程名(參數1, @out_param, @inout_param); -- 位置參數
CALL 存儲過程名(param1 := 值, param3 := @inout_param); -- 命名參數(8.0+)

-- 查看結果(OUT/INOUT 參數)
SELECT @out_param AS 輸出結果, @inout_param AS 輸入輸出結果;

-- 查看存儲過程列表(當前數據庫)
SELECT NAME, PARAM_LIST FROM mysql.proc WHERE db='數據庫名' AND TYPE='PROCEDURE';

-- 查看創建語句
SHOW CREATE PROCEDURE 存儲過程名;

-- 刪除存儲過程
DROP PROCEDURE IF EXISTS 存儲過程名;

接收參數和返回結果

參數類型

作用

傳入方式

內部操作

外部獲取方式

IN

僅傳入值(外部→存儲過程)

常量 / 變量均可

不可修改外部值

無需獲取

OUT

僅輸出值(存儲過程→外部)

必須傳 @ 用户變量

必須賦值

SELECT @變量名

INOUT

雙向交互(傳入 + 輸出)

必須傳 @ 用户變量

可修改並回傳

SELECT @變量名

-- 創建帶三種參數的存儲過程
CREATE PROCEDURE proc_param_demo(
    IN num1 INT,
    OUT sum_result INT,
    INOUT num2 INT
)
BEGIN
    SET sum_result = num1 + num2; -- 計算輸入和,賦值給 OUT
    SET num2 = num2 * 2; -- 修改 INOUT 參數(回傳外部)
END;

-- 調用
SET @inout_num = 5;
CALL proc_param_demo(10, @out_sum, @inout_num);

-- 查看結果
SELECT @out_sum AS 兩數之和, @inout_num AS 修改後的值; -- 輸出:15、10

異常處理

異常處理通過 DECLARE HANDLER 語句聲明,必須放在存儲過程 / 函數代碼塊(BEGIN ... END)的 開頭(變量聲明之後,核心邏輯之前)。

DECLARE 處理器類型 HANDLER FOR 異常類型
BEGIN
    -- 異常處理邏輯(如回滾事務、賦值錯誤信息、記錄日誌)
END;

參數類型 取值 / 選項 作用 處理器類型 EXIT(默認)/ CONTINUE - EXIT:執行處理邏輯後,退出當前代碼塊(存儲過程 / 函數終止);

參數類型

取值 / 選項

作用

處理器類型

EXIT(默認)/ CONTINUE

- EXIT:執行處理邏輯後,退出當前代碼塊(存儲過程 / 函數終止);


- CONTINUE:執行處理邏輯後,繼續執行後續代碼(不終止)。

異常類型

1. SQLEXCEPTION:捕獲所有 SQL 錯誤(推薦,通用);

2. SQLWARNING:捕獲 SQL 警告(如數據截斷);

3. NOT FOUND:捕獲 “無數據返回”(如 SELECT INTO 未查詢到結果);

4. 錯誤碼(如 1062 主鍵衝突、1452 外鍵約束);

5. 多個異常用 OR 連接(如 1062 OR 1452)。

明確需要捕獲的異常範圍(精準捕獲或全局捕獲)。

獲取異常詳情的輔助函數:

  • ERROR_CODE():返回異常的數字錯誤碼(如 1062);
  • SQLSTATE():返回異常的 SQL 標準狀態碼(如 23000 代表約束衝突);
  • MESSAGE_TEXT():返回異常的具體描述信息(如 Duplicate entry '101' for key 'PRIMARY');
-- 異常處理:捕獲所有錯誤,回滾事務
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
    ROLLBACK; -- 回滾未提交的事務
    -- 獲取錯誤詳情(可選,便於排查)
    SET p_result = CONCAT(
        '訂單創建失敗:錯誤碼=', ERROR_CODE(), 
        ', 描述=', MESSAGE_TEXT()
    );
END;



-- 捕獲指定錯誤
-- 捕獲主鍵衝突(錯誤碼 1062)
DECLARE EXIT HANDLER FOR 1062
BEGIN
    SET p_result = CONCAT('用户ID=', p_user_id, ' 已存在,無需重複創建');
END;

-- 捕獲其他錯誤(全局兜底)
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
    SET p_result = '創建失敗:' + MESSAGE_TEXT();
END;



- 當使用 SELECT INTO 賦值時,若未查詢到數據會觸發 NOT FOUND 異常,需單獨處理(避免程序中斷)。
-- 捕獲“無數據”異常(SELECT INTO 未查詢到結果)
DECLARE CONTINUE HANDLER FOR NOT FOUND
BEGIN
    SET p_balance = 0.00; -- 默認餘額為 0
    SET p_result = '用户不存在,餘額默認 0';
END;

存儲過程和自定義函數的區別

對比維度

存儲過程

自定義函數(UDF)

核心用途

複雜流程(事務、批量操作)

簡單計算 / 轉換(數據脱敏、格式轉換)

返回值

支持多個 OUT 參數、結果集

必須返回單個 scalar 值(嵌入 SELECT)

事務支持

支持(COMMIT/ROLLBACK)

不支持

寫操作(INSERT/UPDATE)

支持

禁止(邏輯上不建議)

調用方式

CALL 語句單獨調用

嵌入 SQL(SELECT fn ())