DBeaver中仅${param}和$P{param}能实现安全参数化查询,其他写法如?、:param均无效;必须启用变量替换、避免字符串拼接,并手动指定参数类型以防隐式转换错误。

直接用 ${param} 或 $P{param} 就能防 SQL 注入,前提是别手动拼字符串、别勾选“启用变量替换”以外的危险选项。
参数化查询必须用 ${} 或 $P{} 语法
DBeaver 只识别两种参数标记:简单模式 ${param_name} 和 JasperReports 风格 $P{param_name}。其他写法(比如 ?、:param、@param)不会被识别为参数,而是当作普通文本传给数据库,起不到防注入作用。
- ✅ 正确:
SELECT * FROM users WHERE id = ${user_id} AND status = ${status} - ❌ 错误:
SELECT * FROM users WHERE id = ?(DBeaver 不处理 JDBC 占位符) - ❌ 错误:
SELECT * FROM users WHERE name = ':name'(单引号包住导致字面量解析)
参数名只能含字母、数字、下划线、点号,${order.id} 合法,${order-id} 会解析失败。
执行前必须弹出参数赋值对话框
按 Ctrl+Enter(Windows/Linux)或 Cmd+Enter(macOS)执行时,DBeaver 应自动弹出“SQL 参数”窗口。如果没弹窗,说明:
- SQL 中没有合法的
${...}或$P{...}标记 - 编辑器右下角状态栏显示“变量替换:已禁用”——点击它并启用
- 该 SQL 被保存为“脚本”而非“SQL 编辑器”内容(脚本模式默认不触发参数对话框)
弹窗里填的值会被原样转义后传入 PreparedStatement,不是字符串拼接,所以输入 1 OR 1=1 也不会生效——它只会查 id = '1 OR 1=1' 这个字面值。
类型不匹配会导致隐式转换失败或报错
DBeaver 会尝试从表结构推断参数类型,但推断不准时容易翻车:
- 字段是
INT,却传了字符串${"123"}→ 可能报data type mismatch - 字段是
TIMESTAMP,却传了${DATE:yyyy-MM-dd}→ 日期格式不带时分秒,可能被截断或转成 00:00:00 - 空值处理:填空字符串或
null字面量不会自动转成 SQLNULL,得手动勾选“使用 NULL 值”复选框
强烈建议在参数对话框中点“类型”列手动选对类型,尤其是数字、时间、布尔字段。别依赖自动推断,尤其跨数据库(如从 MySQL 切到 PostgreSQL)时元数据行为不一致。
别把变量系统和参数化查询混用
${USER}、${DATE:...} 属于 DBeaver 的「变量系统」,运行时由客户端替换为字符串;而 ${param} 是「参数化查询」,交由 JDBC PreparedStatement 处理。两者机制完全不同:
- ✅ 安全:
WHERE create_time > ${start_date}→ PreparedStatement 绑定 - ⚠️ 不安全:
WHERE create_time > '${DATE:yyyy-MM-dd}'→ 客户端字符串替换,若变量内容含单引号或 SQL 片段,仍可能被注入
记住一个判断标准:只要值被单引号包住、且外面没套 ${...} 作为参数名,就不是真正的参数化,只是客户端文本替换。
最容易忽略的是类型推断失效场景——比如查 JSON 字段用 WHERE data->>'$.name' = ${name},DBeaver 看不到目标列类型,常默认当字符串处理,但某些数据库驱动对 JSON 路径表达式有特殊要求,这时候必须手动指定参数类型为 VARCHAR 或 JSON(如果驱动支持)。











