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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 19:35:22