java 通过LAZY加载或JOIN FETCH检索关系?

wi3ka0sx  于 2023-04-10  发布在  Java
关注(0)|答案(3)|浏览(139)

假设我有以下实体:

@Entity
public class Foo {
  @Id
  @GeneratedValue(strategy = IDENTITY)
  private Long id;

  @ManyToOne(fetch = LAZY)
  private EntityA a;

  @ManyToOne(fetch = LAZY)
  private EntityB b;

  .
  .
  .

  @ManyToOne(fetch = LAZY)
  private EntityX x;
}

所有关系都是延迟加载的,因为在大多数情况下,业务逻辑不需要它们。接下来,假设有一个端点,它按ID返回特定Foo实体的所有数据。有两个选项可以检索数据:
1.依赖于延迟加载,这意味着X数据库请求将针对X关系进行。考虑到请求是轻量级的,并且每个表只获取1行,这种方法似乎很好。此外,对于代码维护来说,它更令人愉快。
1.编写一个大的HQL查询,JOIN获取所有必要的关系。这种方法只执行一个数据库请求,比上面的选项快几毫秒,但是,hibernate生成一个非常大的SQL,在特定的边缘情况下可能会有性能问题,开发人员必须维护一个大的HQL查询。
在这种情况下有什么最佳实践吗?哪种方法更适合这种特定的场景?

2admgd59

2admgd591#

但是,Hibernate生成一个非常大的SQL,在特定的边缘情况下可能会有性能问题
我不太明白。“可能”这个词似乎在这里起了很大的作用。你有任何实际的证据表明SQL Hibernate会导致糟糕的性能吗?
因为一般来说,加入多个@ManyToOne关联是数据库能够非常有效地完成的事情,并且不太可能导致问题。
需要明确的是,“一个非常大的SQL”无论如何都不是性能差的指标。
因此,您的选择2是推荐。
现在,另一方面,如果你加入多个@OneToMany关联,问题就会出现,所以对于这种情况,可能需要考虑更奇特的解决方案,例如,使用FetchMode.SUBSELECT。但这不是你在上面的代码中展示的情况。

xj3cbfub

xj3cbfub2#

我建议分成两种方法:

List<Foo> getById(Long id);

@Query("SELECT foo FROM Foo foo JOIN FETCH...")
List<Foo> getByIdIncludeRef(Long id);
5t7ly7z5

5t7ly7z53#

Hibernate Criteria提供了另一个选项来实现这一点。您可以使用setFetchMode()在运行时指定关联获取语义。像这样:

List cats = session.createCriteria(Foo.class)
    .setFetchMode("a", FetchMode.EAGER)
    .setFetchMode("b", FetchMode.EAGER)
    // ...
    .setFetchMode("x", FetchMode.EAGER)
    .list();

使用这种方法,您可以在大多数用例中保留实体中的延迟加载设置。只有在需要使用引用加载胖对象的端点上-使用上面的代码。Hibernate将生成一个包含所有连接的查询。正是您在第2点中想要的。但没有硬编码和容易出错的查询字符串。

相关问题