You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot多关键词模糊查询失效:含%字符无结果返回

Spring Boot PostgreSQL多关键词模糊查询问题解决

问题场景

需要实现多关键词模糊查询产品,比如搜索“wet food”时返回包含“wet”和“food”的产品(如“wet cat food”)。当前做法是将搜索词的空格替换为%,调用productRepository.findProductsByNameContainingIgnoreCase方法,但数据库存在匹配数据却始终返回空结果。直接编写SQL语句执行正常,但Spring Boot代码无法生效。

问题原因

Spring Data JPA的ContainingIgnoreCase系列方法会自动做两件事:

  1. 在参数前后添加%通配符
  2. 将参数中自带的%、_等通配符转义为普通字符(防止SQL注入)

所以当你传入处理后的wet%food时,实际生成的SQL条件是:

WHERE name ILIKE '%wet\%food%'

这里的\%是转义后的普通字符,不再作为通配符使用,导致无法匹配到包含“wet”和“food”的产品。

解决方案

方案1:自定义JPQL查询

直接编写JPQL语句,手动控制通配符的使用,避免JPA自动转义。

首先在Repository接口中定义自定义查询:

public interface ProductRepository extends JpaRepository<Product, Long> {
    @Query("SELECT p FROM Product p WHERE p.name ILIKE :searchPattern")
    List<Product> findProductsByNameMatching(@Param("searchPattern") String searchPattern);
}

然后在业务层处理搜索词,将空格替换为%并前后添加%:

String searchTerm = "wet food";
// 转换为 %wet%food% 格式
String searchPattern = "%" + searchTerm.replace(" ", "%") + "%";
List<Product> products = productRepository.findProductsByNameMatching(searchPattern);

方案2:使用Specification动态构建查询

拆分搜索关键词,为每个关键词单独添加模糊查询条件,用AND连接,更灵活且避免通配符转义问题。

先编写Specification工具类:

public class ProductSpecifications {
    public static Specification<Product> nameContainsAllKeywords(String keywords) {
        return (root, query, criteriaBuilder) -> {
            // 按空格拆分关键词(支持多个连续空格)
            String[] keywordArray = keywords.split("\\s+");
            Predicate[] predicates = new Predicate[keywordArray.length];
            
            for (int i = 0; i < keywordArray.length; i++) {
                String keyword = keywordArray[i].toLowerCase();
                // 为每个关键词添加模糊查询条件
                predicates[i] = criteriaBuilder.like(
                    criteriaBuilder.lower(root.get("name")),
                    "%" + keyword + "%"
                );
            }
            // 所有关键词条件必须同时满足
            return criteriaBuilder.and(predicates);
        };
    }
}

然后调用Repository的findAll方法传入Specification:

List<Product> products = productRepository.findAll(
    ProductSpecifications.nameContainsAllKeywords("wet food")
);

内容的提问来源于stack exchange,提问作者ElectroniQ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 19:12:42