Java中 Spring Data JPA 的 Specification 中怎么配合通配符构造复杂查询

作者:袖梨 2026-07-14
Spring Data JPA 的 Specification 通过 CriteriaBuilder 的 like() 配合 concat() 或字符串拼接实现模糊查询,支持前缀、后缀、全模糊匹配;推荐用 lower() 统一转小写以保证跨库一致性,并注意防止 SQL 注入。

` 中怎么配合通配符构造复杂查询">

Spring Data JPA 的 Specification 本身不直接支持 SQL 通配符(如 %_),但你可以通过 CriteriaBuilderlike()ilike()(PostgreSQL)或 lower()/upper() 配合字符串拼接,安全地构造带通配符的模糊查询。

like() + concat() 实现前后/左右模糊匹配

like() 是标准 JPA 方法,需手动拼接通配符。关键点是:通配符必须作为字符串值的一部分传入,不能写在字段名里;且推荐使用 CriteriaBuilder#concat() 或 Java 字符串拼接(注意防止 SQL 注入)。

  • 前缀匹配(以 xxx 开头):cb.like(root.get("name"), cb.concat(cb.literal("xxx"), "%"))
  • 后缀匹配(以 xxx 结尾):cb.like(root.get("name"), cb.concat("%", cb.literal("xxx")))
  • 全模糊(包含 xxx):cb.like(root.get("name"), cb.concat("%", cb.concat(cb.literal("xxx"), "%")))
  • 更简洁写法(Java 字符串拼接):cb.like(root.get("name"), "%" + keyword + "%") —— 仅限 keyword 已校验/转义,否则有注入风险

大小写不敏感查询:用 lower() 统一转换

数据库默认 like 区分大小写(如 MySQL 默认不区分,但 H2/PostgreSQL 区分)。为确保跨库一致性,建议统一转小写:

  • cb.like(cb.lower(root.get("name")), "%" + keyword.toLowerCase() + "%")
  • 也可用 cb.equal(cb.lower(root.get("name")), keyword.toLowerCase()) 做精确小写匹配

组合多个 like 条件:用 and() / or() 连接

Specification 天然支持逻辑组合。例如“姓名或邮箱包含关键词”:

立即学习“Java免费学习笔记(深入)”;

  • cb.or(
  •   cb.like(cb.lower(root.get("name")), "%" + kw + "%"),
  •   cb.like(cb.lower(root.get("email")), "%" + kw + "%")
  • )

注意:多个 like 同时存在时,数据库可能无法有效使用索引,大数据量下建议配合全文检索或添加函数索引(如 PostgreSQL 的 LOWER(name) 索引)。

避免 SQL 注入:永远不要拼接用户输入到 like 模式中

keyword 若来自前端,需清理特殊通配符(%_)或设置 escape 字符:

  • 禁用用户输入通配符:keyword = keyword.replaceAll("[%_]", "")
  • 启用自定义 escape(如用 ):cb.like(root.get("desc"), "%"+kw+"%", ''),然后要求用户写 abc% 表示查字面量 %
  • JPA 2.1+ 支持 escape() 方法:cb.like(root.get("desc"), "%" + kw, '')

相关文章

精彩推荐