命名参数绑定必须调用setParameter()才生效:createQuery()仅解析HQL字符串,不校验参数绑定;漏调setParameter会抛QueryParameterException导致查询失败,而非SQL注入。

命名参数绑定必须调用 setParameter() 才生效
Hibernate 6 的 createQuery() 或 createSQLQuery() 只解析字符串,不校验参数是否绑定。写 "FROM User WHERE name = :name" 本身不防注入,漏掉 setParameter("name", userInput) 会直接抛 QueryParameterException,查询失败——这不是注入,但业务逻辑断了。
常见错误包括:
-
:userName和setParameter("username", value)拼写或大小写不一致 → 运行时报错 - 只创建
Query对象,没调后续setParameter()→ 查询返回空或异常,IDE 不提示 - 误用已废弃的
setString("name", value)→ Hibernate 6 类型推导弱,枚举、LocalDateTime 等可能绑定失败
IN 子句必须用 setParameterList(),不能传整个 List
把 List<long></long> 直接塞给 setParameter("ids", idList) 是典型错误。Hibernate 会把它当单个对象处理,生成类似 WHERE id = ?(? 对应整个 List),导致语法错误或全表扫描。
正确做法只有这一种:
- 必须用
setParameterList("ids", idList),Hibernate 才会展开为WHERE id IN (?, ?, ?) - 空列表要提前判断:
setParameterList()不接受空集合,会抛IllegalArgumentException - 禁止手动拼
"IN (" + String.join(",", ids) + ")"→ 注入风险 + 类型转换问题(比如字符串带单引号)
表名、字段名、排序方向无法参数化,必须白名单校验
HQL 和原生 SQL 都不支持把 FROM 后的表名、ORDER BY 后的字段、ASC/DESC 当参数绑定。任何字符串拼接都是危险的。
这些写法全是错的:
session.createQuery("FROM " + tableName + " WHERE id = :id")session.createQuery("ORDER BY " + sortField + " " + sortOrder)
必须硬性校验:
- 表名/字段名 → 映射到枚举,或用
Set.of("user", "order").contains(input)校验 - 排序方向 → 只允许字面量
"ASC"或"DESC",禁止动态传入
Hibernate 6 原生 SQL 中别名和结果映射必须严格匹配 DTO 属性名
执行原生 SQL 时,addEntity() 或 addScalar() 依赖列别名与 Java 对象属性名完全一致。例如:
SELECT u.id AS id, u.email AS email FROM users u
如果 DTO 是 UserDto,且含 id 和 email 字段,才能自动映射。别名写成 user_id 或 EMAIL 就会失败。
还要注意:
- 原生 SQL 的占位符下标从 1 开始(
setParameter(1, value)),不是 HQL 的从 0 开始 -
executeUpdate()返回受影响行数,不是结果集;查数据要用list()或uniqueResult() - 别名缺失或大小写不一致是
Hibernate 6常见静默失败点,日志里往往只报Unable to extract JDBC value for position '1',实际是别名没对上

















