存儲過程中需根據傳入參數動態構建表名、列名、WHERE 條件等無法用預處理佔位符(?)表示的 SQL 片段。
CONCAT / CONCAT_WS 構建 SQL 字符串@sqlPREPARE stmt FROM @sql 解析準備EXECUTE stmt 執行DEALLOCATE PREPARE stmt 釋放DELIMITER $$
CREATE PROCEDURE `sp_dynamic_update`(
IN p_table VARCHAR(128),
IN p_column VARCHAR(128),
IN p_new_value VARCHAR(1000),
IN p_where VARCHAR(4000)
)
BEGIN
DECLARE v_sql VARCHAR(4000);
-- 構建動態 SQL
SET v_sql = CONCAT_WS(' ',
'UPDATE', p_table,
'SET', CONCAT(p_column, '=', QUOTE(p_new_value)),
'WHERE', p_where
);
-- 準備並執行
SET @sql = v_sql;
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
CALL sp_dynamic_update('users', 'status', '1', 'id = 100');
-- 等效於:UPDATE users SET status = '1' WHERE id = 100
QUOTE() 轉義或預處理佔位符@sql 作用域會話級,存儲過程結束後仍存在,建議執行後 SET @sql = NULL; 清理。
LOCK TABLES、PREPARE 本身)max_prepared_stmt_count 限制(默認 16382)CREATE PROCEDURE `sp_dynamic_select`(
IN p_table VARCHAR(64),
IN p_where VARCHAR(500),
IN p_limit INT
)
BEGIN
SET @sql = CONCAT('SELECT * FROM ', p_table, ' WHERE ', p_where, ' LIMIT ?');
PREPARE stmt FROM @sql;
SET @lim = p_limit;
EXECUTE stmt USING @lim;
DEALLOCATE PREPARE stmt;
END
關鍵:USING @lim 綁定佔位符參數,實現「動態結構 + 參數化值」雙重安全。
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
@errno = MYSQL_ERRNO, @msg = MESSAGE_TEXT;
SELECT CONCAT('Error ', @errno, ': ', @msg) AS error_info;
DEALLOCATE PREPARE stmt; -- 確保釋放
END;
-- 動態 SQL 邏輯
SET @sql = ...;
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
MySQL 存儲過程動態 SQL 核心模式:構建字符串 → 用戶變量 → PREPARE → EXECUTE → DEALLOCATE。配合白名單驗證表/列名、QUOTE() 轉義值、參數化佔位符、異常處理釋放資源,即可安全靈活實現運行時 SQL 構建。