Spring Boot JPA如何结合LIKE与OR实现多字段模糊匹配派生查询
完全可以不使用@Query注解,仅通过JPA派生查询方法的命名规则实现三个字段的模糊匹配,你之前写findByNameLikeOrAuthorLikeOrDescriptionLike没拿到预期结果,核心原因是对Like关键字的派生逻辑理解有误。
你之前两次写法不生效的根因很明确:
- 初始写法
findByNameOrAuthorOrDescription生成的SQL用=做精确匹配,只能匹配和传入值完全一致的字段内容,自然无法匹配部分命中的场景 - 后续改成带
Like的方法后,JPA只会为对应字段生成LIKE ?的查询条件,不会自动给参数拼接通配符%,你直接传入gandhi作为参数,最终执行的条件等价于author LIKE 'gandhi',和精确匹配效果完全一致,所以无法命中Mahatama Gandhi这类值。
你可以选以下两种符合JPA派生规则的写法,都不需要自定义@Query:
方案1:保留Like关键字,手动拼接通配符
你定义的findByNameLikeOrAuthorLikeOrDescriptionLike方法本身语法是合法的,只需要在调用方法前,给需要模糊匹配的参数手动拼接前后通配符即可:
// Service层调用示例 public List<BookRepoRto> searchBooks(String name, String author, String description) { // 做空判断,避免null值被拼接成"%null%"导致查询异常 String nameParam = name == null ? null : "%" + name + "%"; String authorParam = author == null ? null : "%" + author + "%"; String descParam = description == null ? null : "%" + description + "%"; return bookRepo.findByNameLikeOrAuthorLikeOrDescriptionLike(nameParam, authorParam, descParam); }
这种方式灵活性更高,如果你需要做前缀匹配、后缀匹配,可以自行调整通配符的位置(比如前缀匹配就拼参数%)。
方案2:使用Containing关键字,自动实现包含匹配
JPA派生查询提供了专门的Containing关键字,会自动给参数两边拼接%生成模糊查询条件,不需要手动处理参数,方法定义如下:
public List<BookRepoRto> findByNameContainingOrAuthorContainingOrDescriptionContaining(String name, String author, String description);
该方法生成的SQL等价于:
SELECT * FROM book WHERE name LIKE CONCAT('%', ?1, '%') OR author LIKE CONCAT('%', ?2, '%') OR description LIKE CONCAT('%', ?3, '%')
直接传入用户输入的原始参数值(比如gandhi),就能命中任意位置包含该字符串的字段,完全满足你的需求。
如果需要适配用户输入大小写不固定的场景(比如用户输入小写gandhi也能匹配大写开头的Gandhi),可以在关键字后追加IgnoreCase实现忽略大小写匹配,方法定义示例:
public List<BookRepoRto> findByNameContainingIgnoreCaseOrAuthorContainingIgnoreCaseOrDescriptionContainingIgnoreCase(String name, String author, String description);
除了Containing之外,JPA还内置了两个常用的模糊匹配关键字,可以按需选用:
StartingWith:自动给参数后缀拼接%,实现前缀匹配EndingWith:自动给参数前缀拼接%,实现后缀匹配
注意:如果你的业务场景支持部分查询参数为空(比如只传name,author和description不传),直接传null会导致对应LIKE条件恒不成立,建议结合
IsNull条件做适配,或者使用Specification实现动态查询,不过这已经超出纯派生查询的范畴了。
内容的提问来源于stack exchange,提问作者Palak Kharbanda

