如何编写Spring Data JPA可选参数查询方法并修复现有问题
修复Spring Data JPA动态查询的三个问题
问题分析
你当前的查询存在三个核心问题:
- Title模糊查询失效:直接写
%:title%会在title为null时生成%null%的匹配条件,无法忽略该字段,且未实现忽略大小写的模糊匹配。 - createdTime条件逻辑错误:原条件会在
startTime或endTime为0时强制添加无效约束,导致符合条件的数据被过滤。 - 可选字段缺失时无结果:
userKey等可选字段为null时,原条件会错误过滤掉非null的匹配数据。
修复后的查询代码
@Query("select m from MaterialMetadata m where m.myKey = :myKey and m.statusType = :statusType " + "and ( (:startTime = 0 and :endTime = 0) or (m.createdTime >= :startTime and :endTime = 0) or (m.createdTime <= :endTime and :startTime = 0) or (m.createdTime >= :startTime and m.createdTime <= :endTime) ) " + "and (:userKey is null or m.userKey = :userKey) " + "and (:title is null or lower(m.title) like lower(concat('%', :title, '%')))") Page<MaterialMetadata> findByMyKeyAndStatusTypeWithOptionalFilters( @Param("myKey") String myKey, @Param("statusType") StatusType statusType, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userKey") String userKey, @Param("title") String title, Pageable pageable);
关键修改说明
Title模糊查询修复
- 先判断
title是否为null,是则跳过该条件;否则用concat('%', :title, '%')生成模糊匹配规则,同时通过lower()实现忽略大小写的查询,完全符合需求。
- 先判断
createdTime条件修复
- 明确区分四种时间查询场景:
- 若
startTime和endTime均为0,直接忽略时间条件; - 仅
startTime有值,查询createdTime >= startTime; - 仅
endTime有值,查询createdTime <= endTime; - 两者均有值,查询时间区间内的数据。
- 若
- 彻底解决了原逻辑中0值导致的无结果问题。
- 明确区分四种时间查询场景:
可选字段缺失修复
- 将
(m.userKey= :userKey or :userKey is null)调整为(:userKey is null or m.userKey = :userKey),优先判断参数是否为null,是则跳过该条件,确保可选字段缺失时不会过滤有效数据。
- 将
额外注意事项
如果createdTime是Date或Timestamp类型而非long,需要将long参数转换为数据库支持的时间类型,例如:
// 针对毫秒级时间戳转秒级适配PostgreSQL的to_timestamp函数 @Query("select m from MaterialMetadata m where m.myKey = :myKey and m.statusType = :statusType " + "and ( (:startTime = 0 and :endTime = 0) or (m.createdTime >= to_timestamp(:startTime / 1000) and :endTime = 0) or (m.createdTime <= to_timestamp(:endTime / 1000) and :startTime = 0) or (m.createdTime >= to_timestamp(:startTime / 1000) and m.createdTime <= to_timestamp(:endTime / 1000)) ) " + "and (:userKey is null or m.userKey = :userKey) " + "and (:title is null or lower(m.title) like lower(concat('%', :title, '%')))")
内容的提问来源于stack exchange,提问作者Yashika Chandra
相关产品推荐
相关产品推荐

