存儲過程(Procedure)與函數(Function)是 MySQL 服務端程式化的核心。本文系統梳理創建語法、特性子句、權限模型(DEFINER/INVOKER)、查看元數據、以及主從複製環境下的 log_bin_trust_function_creators 陷阱與解決方案。
| 特性 | 存儲過程 | 函數 |
|---|---|---|
| 返回值 | 無(通過 OUT/INOUT 參數) | 強制 RETURNS type + RETURN expr |
| 參數模式 | IN / OUT / INOUT | 僅 IN |
| 調用方式 | CALL sp_name() | SQL 表達式中直接調用 fn_name() |
| 事務控制 | 支持 START TRANSACTION/COMMIT/ROLLBACK | 隱式只讀,不可顯式事務 |
CREATE PROCEDURE sp_name ([params])
[characteristic ...] routine_body
characteristic:
LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
| 屬性 | 含義 | 默認值 | 複製影響 |
|---|---|---|---|
| DETERMINISTIC | 相同輸入必產生相同輸出 | NOT DETERMINISTIC | 複製安全需顯式聲明 |
| READS SQL DATA | 僅讀數據,不修改 | CONTAINS SQL | 安全,允許複製 |
| MODIFIES SQL DATA | 包含寫操作 | - | 主從可能數據不一致 |
| SQL SECURITY DEFINER | 以創建者權限執行 | DEFINER | 需創建者有目標對象權限 |
| SQL SECURITY INVOKER | 以調用者權限執行 | - | 調用者需有權限 |
報錯: Error 1418: This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA...
原因: 啟用 log_bin 時,MySQL 強制要求函數顯式聲明確定性或只讀特性,防止主從數據漂移。
SET GLOBAL log_bin_trust_function_creators = 1;
-- 永久生效需寫入 my.cnf [mysqld] 區段
⚠️ 僅在確認函數邏輯在主從完全一致時使用,否則可能導致複製錯誤。
CREATE FUNCTION fn_demo(p_id INT) RETURNS INT
DETERMINISTIC READS SQL DATA
BEGIN
DECLARE v_cnt INT;
SELECT COUNT(*) INTO v_cnt FROM t1 WHERE id = p_id;
RETURN v_cnt;
END;
存儲過程同理,建議在創建腳本中強制包含 DETERMINISTIC + READS SQL DATA / MODIFIES SQL DATA。
-- 1. 狀態概覽
SHOW PROCEDURE STATUS LIKE 'sp_demo'\G;
-- 2. 創建語句(含 characteristic)
SHOW CREATE PROCEDURE sp_demo\G;
-- 3. 完整元數據(information_schema)
SELECT * FROM information_schema.ROUTINES
WHERE ROUTINE_SCHEMA = 'mydb' AND ROUTINE_NAME = 'sp_demo'\G;
-- 僅能修改 characteristic,不可改 routine_body
ALTER PROCEDURE sp_name [characteristic ...];
-- 刪除
DROP PROCEDURE [IF EXISTS] sp_name;
DROP FUNCTION [IF EXISTS] fn_name;
DETERMINISTIC + 數據訪問特性 + SQL SECURITY。SQL SECURITY INVOKER,遵循最小權限原則。PREPARE),若必須動態則嚴格驗證輸入防注入。SHOW REPLICA STATUS 確認無複製錯誤。規範的例程開發流程 = 顯式特性聲明 + 權限最小化 + 複製安全驗證 + 自動化測試,這是從「能用」到「可信」的關鍵跨越。