【问题标题】:Spring Data/JPS (N+1) SELECTs with OneToOne associations具有一对一关联的 Spring Data/JPA (N+1) SELECT
【发布时间】:2016-07-01 11:20:43
【问题描述】:

在我的 Spring Data 应用程序中,我遇到了 (N+1) 个选择问题。

我有以下 Spring Data 实体:

@Entity
@Table(name = "card_categories")
public class CardCategory extends BaseEntity implements Serializable {

    @Id
    @SequenceGenerator(name = "card_categories_id_seq", sequenceName = "card_categories_id_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "card_categories_id_seq")
    private Long id;

    private String name;
...

}

@Entity
@Table(name = "levels")
public class Level extends BaseEntity implements Serializable {

    @Id
    @SequenceGenerator(name = "levels_id_seq", sequenceName = "levels_id_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "levels_id_seq")
    private Long id;

    private String name;
...
}

@Entity
@Table(name = "card_categories_levels")
public class CardCategoryLevel extends BaseEntity implements Serializable {

    @Id
    @SequenceGenerator(name = "card_categories_levels_id_seq", sequenceName = "card_categories_levels_id_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "card_categories_levels_id_seq")
    private Long id;

    @OneToOne
    @JoinColumn(name = "card_category_id")
    private CardCategory cardCategory;

    @OneToOne
    @JoinColumn(name = "level_id")
    private Level level;
...

}

和空的 Spring Data 存储库:

@Repository
public interface CardCategoryLevelRepository extends JpaRepository<CardCategoryLevel, Long> {
}

当我尝试通过 cardCategoryLevelRepository.findAll() 方法获取所有 CardCategoryLevel 实体时,它会为我的 card_categories_levels 表中的每一行生成 3 个 SELECT。

为了使用单个 JOIN 而不是 N+1 SELECTs,我重新实现了我的 CardCategoryLevelRepository:

@Repository
public interface CardCategoryLevelRepository extends JpaRepository<CardCategoryLevel, Long> {

    @Query(value = "SELECT ccl FROM CardCategoryLevel ccl LEFT JOIN FETCH ccl.cardCategory cc LEFT JOIN FETCH ccl.level l where cc = :cardCategory and l = :level")
    CardCategoryLevel findByCardCategoryAndLevel(@Param("cardCategory") CardCategory cardCategory, @Param("level") Level level);

    @Override
    @Query(value = "SELECT ccl FROM CardCategoryLevel ccl LEFT JOIN FETCH ccl.cardCategory LEFT JOIN FETCH ccl.level")
    List<CardCategoryLevel> findAll();

}

但我不确定我是否以正确的最佳方式做到了。

请验证我的方法并告诉它对于 Spring Data 中 OneToOne 关联的 (N+1) SELECTs 问题是否是最佳解决方法,以及解决它的最佳方法是什么。

我应该保持原样还是可以转移到其他抽象......例如像 QueryDSL 或类似的东西?

【问题讨论】:

  • 实体图为 N+1 问题提供了很好的解决方案,以防万一您使用 JPA 2.1:thoughts-on-java.org/jpa-21-entity-graph-part-1-named-entity
  • @XtremeBiker 感谢这篇精彩的文章。还有一个问题 - 它如何与 Spring Data 一起工作。我的意思是 - 我需要直接使用 EntityManager 还是可以以更抽象的方式与 Spring Data Repositories 集成?
  • 最新版本的 Spring Data 附带符合 JPA 2.1 的实现,如 Hibernate 4.3+ or 5.0+。底层实现关心它,而不是 Spring 本身。
  • 谢谢,这绝对是我在 JPA 见过的最好的东西!
  • 将它作为答案对您来说是正确的吗?这样我们就可以回答问题。

标签: spring jpa spring-data spring-data-jpa querydsl


【解决方案1】:

感谢Xtreme Biker 我用实体图和QueryDSL 重新实现了我的解决方案

【讨论】:

  • 您能否提供一个工作示例,说明您如何与 Spring Data JPA 中的 EntityManager 进行交互?
  • 事实证明 Spring Data JPA 具有使用实体图的注释,而无需访问底层 EntityManager。我在这里找到了一个例子:codingexplained.com/coding/java/spring-framework/….
猜你喜欢
  • 2018-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-14
  • 1970-01-01
  • 1970-01-01
  • 2021-11-06
相关资源
最近更新 更多