Spring JPQL查询返回重复结果,Fetch Join处理无效
JPQL查询结果重复5倍的问题解决
问题根源
你的问题不是N+1查询,而是关联查询产生了笛卡尔积:
- 子查询返回多个符合
level_2_Title条件的Lv3实例 - 主查询将Lv4与这些Lv3关联,同时又关联了TitleInfo和Title表,若Title表中对应多条匹配记录,会导致每条Lv4被多次匹配,最终结果膨胀为5倍。
修复方案
方案1:添加DISTINCT去重
在JPQL的SELECT语句后加上DISTINCT,强制返回唯一的Lv4实体:
@Repository public class Lv4Repository { @PersistenceContext private EntityManager em; public List<Lv4> findLv4ByLv3Id(String level_2_Title, String level_3_Title) { return em.createQuery("select DISTINCT l4 from Lv4 l4 join Lv3 as l3 on l4.lv3 = " + "(select l3 from Lv3 l3 join Lv2 as l2 on l3.lv2 = l2 " + "join TitleInfo as ti on l2.metaInfo = ti.metaInfo " + "join Title as t on ti.id = t.titleInfo.id " + "where t.titleText like concat('%',:level_2_Title,'%'))" + "join TitleInfo as ti on l3.metaInfo = ti.metaInfo " + "join Title as t on ti.id = t.titleInfo.id " + "where t.titleText =: level_3_Title", Lv4.class) .setParameter("level_2_Title", level_2_Title) .setParameter("level_3_Title", level_3_Title) .getResultList(); } }
方案2:重构查询逻辑(更优)
去掉冗余的嵌套子查询,直接通过实体关联路径过滤,减少不必要的join,从根源避免笛卡尔积:
@Repository public class Lv4Repository { @PersistenceContext private EntityManager em; public List<Lv4> findLv4ByLv3Id(String level_2_Title, String level_3_Title) { String jpql = """ select DISTINCT l4 from Lv4 l4 join l4.lv3 l3 join l3.lv2 l2 join l2.metaInfo ti2 join Title t2 on ti2.id = t2.titleInfo.id join l3.metaInfo ti3 join Title t3 on ti3.id = t3.titleInfo.id where t2.titleText like concat('%', :level_2_Title, '%') and t3.titleText = :level_3_Title """; return em.createQuery(jpql, Lv4.class) .setParameter("level_2_Title", level_2_Title) .setParameter("level_3_Title", level_3_Title) .getResultList(); } }
关键说明
- N+1查询是指先查询主表数据,再循环查询关联表的多次DB请求,和你当前单次查询返回重复结果的问题完全不同。
- 若使用Spring Data JPA,也可以通过
@Query注解结合distinct简化代码,或用Specification构建动态查询。
内容的提问来源于stack exchange,提问作者Sunwoo Jung
相关产品推荐
相关产品推荐

