存儲過程將業務邏輯下沉至數據庫層,減少網絡交互、封裝複雜事務。本文從零開始構建認知體系:語法結構、三種參數模式(IN/OUT/INOUT)、分隔符機制、修改/刪除限制、跨過程依賴風險與最佳實踐。
DELIMITER //
CREATE PROCEDURE add_test_data()
BEGIN
DECLARE n INT DEFAULT 0;
WHILE n < 100000 DO
INSERT INTO proced(name, type) VALUES ('TraceBlog', 'onmpw');
SET n = n + 1;
END WHILE;
END//
DELIMITER ;
CALL add_test_data();
MySQL 客戶端默認以 ; 判斷語句結束。存儲過程體內包含多條語句,若不修改分隔符,客戶端會在第一個 ; 就提交解析,導致語法錯誤。DELIMITER // 將語句結束符臨時改為 //,創建完成後 DELIMITER ; 恢復默認。
| 模式 | 方向 | 調用端初始化 | 過程內可修改 | 調用端可見變化 | 典型場景 |
|---|---|---|---|---|---|
| IN | 輸入 | 必須 | 可(局部副本) | 不可見 | 查詢條件、業務參數 |
| OUT | 輸出 | 無需(建議初始化) | 必須賦值 | 可見 | 返回統計結果、狀態碼 |
| INOUT | 雙向 | 必須 | 可修改 | 可見 | 累加計數器、狀態機流轉 |
-- IN:查詢部門人數
CREATE PROCEDURE dept_cnt(IN p_dept INT, OUT p_cnt INT)
BEGIN SELECT COUNT(*) INTO p_cnt FROM emp WHERE depid = p_dept; END;
-- OUT:獲取最大 ID
CREATE PROCEDURE max_id(OUT p_max INT)
BEGIN SELECT MAX(id) INTO p_max FROM emp; END;
-- INOUT:遞增計數器
CREATE PROCEDURE incr(INOUT p_val INT)
BEGIN SET p_val = p_val + 1; END;
-- 調用驗證
SET @v = 5; CALL incr(@v); SELECT @v; -- 返回 6
ALTER PROCEDURE 僅能修改 characteristic(如 SQL SECURITY、COMMENT),不可修改 routine_body。需 DROP + CREATE 重建邏輯。DROP PROCEDURE 前必須確認無其他過程調用它,否則調用方運行時報 ERROR 1305: PROCEDURE ... does not exist。
SELECT ROUTINE_SCHEMA, ROUTINE_NAME
FROM information_schema.ROUTINES
WHERE ROUTINE_DEFINITION LIKE '%target_proc_name%';
CREATE PROCEDURE sensitive_op()
SQL SECURITY DEFINER -- 默認:以創建者(root)權限執行
BEGIN ... END;
CREATE PROCEDURE audit_safe()
SQL SECURITY INVOKER -- 以調用者(app_user)權限執行
BEGIN ... END;
選型原則: 涉及敏感數據讀寫用 DEFINER(配合最小權限賬號);業務邏輯校驗用 INVOKER,天然實現行級權限控制。
WHERE col = param 會匹配到列而非參數(建議參數加 p_ 前綴)。SELECT *,顯式列出列名,防止表結構變更導致行構造錯誤。DECLARE CONTINUE HANDLER FOR SQLEXCEPTION ... 統一捕獲並記錄錯誤碼,最後 ROLLBACK。CREATE PROCEDURE 腳本納入 Git,通過 Flyway/Liquibase 管理部署。存儲過程是把雙刃劍:用好能封裝核心業務邏輯、提升性能與安全性;用不好會變成難以維護、難以擴展、難以測試的「黑盒」。建議團隊制定《存儲過程開發規範》,限制使用場景至「高頻、強一致性、跨語言複用」三類核心業務。