| 限制 | 說明 | 版本 |
| 表名/欄位名不可作參數 | PREPARE stmt FROM 'SELECT * FROM ?' 報錯 | 5.0.24+ 仍不支援 |
| EXECUTE USING 僅接受 @session 變數 | DECLARE 區域變數、參數變數皆不可用 | 所有版本 |
| PREPARE 需 5.0.13+ | 存儲程序中才支援動態 SQL | 5.0.13+ |
標準動態 SQL 模板
DROP PROCEDURE IF EXISTS `up_common_select`;
CREATE PROCEDURE `up_common_select`(IN t_name VARCHAR(64))
BEGIN
DECLARE v_sql VARCHAR(500);
-- 1. 組裝 SQL 字串(解決表名參數化)
SET v_sql = CONCAT('SELECT * FROM `', t_name, '`');
-- 2. 必須轉給 @session 變數
SET @v_sql = v_sql;
-- 3. PREPARE / EXECUTE / DEALLOCATE
PREPARE stmt FROM @v_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END;
-- 呼叫
CALL up_common_select('admin_authority');
進階:帶參數的動態查詢
CREATE PROCEDURE `search_users`(
IN tbl VARCHAR(64),
IN keyword VARCHAR(100),
IN lim INT
)
BEGIN
SET @sql = CONCAT('SELECT * FROM `', tbl, '` WHERE name LIKE ? LIMIT ?');
SET @kw = CONCAT('%', keyword, '%');
SET @lim = lim;
PREPARE stmt FROM @sql;
EXECUTE stmt USING @kw, @lim; -- 必須用 @變數
DEALLOCATE PREPARE stmt;
END;
安全防注入檢查清單
- 表名/欄位名:白名單驗證,不可直接拼接用戶輸入
- 值參數:務必用 PREPARE + USING,絕不拼接
- 識別符反引號:
CONCAT('`', REPLACE(identifier, '`', ''), '`')
- 限制
max_prepared_stmt_count 防止洩漏
常見錯誤與修正
| 錯誤寫法 | 正確寫法 |
PREPARE stmt FROM 'SELECT * FROM ?'; | SET @sql = CONCAT('SELECT * FROM `', @tbl, '`'); PREPARE stmt FROM @sql; |
EXECUTE stmt USING v_param; (區域變數) | SET @v_param = v_param; EXECUTE stmt USING @v_param; |
| 忘記 DEALLOCATE | 必須成對 DEALLOCATE PREPARE stmt; |
效能提示
- 動態 SQL 無法使用查詢快取(已移除)
- 頻繁 PREPARE 產生解析開銷,熱點路徑改用固定 SQL
PREPARE 會話級持久,連線池復用時注意清理
- 上一篇文章: MySQL 權限系統深度解析:用戶認證、主機匹配、權限表結構與最佳實踐
- 下一篇文章: Windows 下 MySQL 備份還原完整操作指南:mysqldump、mysqladmin 與命令列實戰
Copyright ©
程式碼之家 All Rights Reserved