为什么 JPA 默认使用 FetchType EAGER 作为@ManyToOne关系



我注意到@ManyToOne映射的默认FetchType在 JPA 和 Hibernate 中EAGER,而对于@OneToMany映射,默认FetchTypeLAZY

这背后的具体原因是什么?

JPA 2.0 spec 开始,默认值如下所示:

OneToMany: LAZY
ManyToOne: EAGER
ManyToMany: LAZY
OneToOne: EAGER

冬眠中,一切都是懒惰的

来自Hibernate Docs,

默认情况下,Hibernate对集合和 单值关联的延迟代理提取。这些默认值 对于大多数应用程序中的大多数关联都有意义。

为了回答你的问题,Hibernate是JPA标准的实现。Hibernate有自己的操作怪癖,但根据Hibernate文档

By default, Hibernate uses lazy select fetching for collections and lazy proxy fetching for single-valued associations. These defaults make sense for most associations in the majority of applications.

因此,Hibernate将始终使用延迟获取策略加载任何对象,无论您声明了哪种类型的关系。

JPA Spec 假设通常大多数应用程序默认要求单例关系是 Eager 的,而多值关系默认是惰性的。

请参阅此处了解更多信息

JPA gotcha

将它们设置为 EAGER 的原因是,早期的 JPA 1.0 设计人员认为强制 JPA 实现以支持动态初始化代理将是一个非常强大的要求。但是,由于没有代理,性能将受到巨大影响,因此所有提供商都支持 LAZY 关联。

避免FetchType.EAGER

@ManyToOne@OneToOne关联使用默认的 EAGER 获取策略是一个糟糕的主意,因为您很容易最终遇到 N+1 查询问题。

使用 Hibernate 时,一旦关联设置为 FetchType.EAGER ,就无法再在查询时懒惰地获取它。因此,无论当前业务用例是否需要它,您都将始终获取该关系。

默认使用FetchType.LAZY

因此,您最好默认对所有关联使用 FetchType.LAZY

FetchType.EAGER不同,FetchType.LAZY关系可以在查询时使用JOIN FETCH子句急切地获取。

您唯一需要注意的是,如果您需要在 JPA EntityManager关闭后访问关联,则需要在当前运行的持久性上下文的上下文中获取该关联。否则,你会得到一个LazyInitializationException

如果你仔细观察它,你会发现如果关系以Many关键字结束,即 OneToManyManyToMany,它是懒惰的。如果它以One结尾,即 ManyToOneOneToOne,它是急切的。所以问题是,如果你只需要加载一个对象,它会非常快速地获取它。但是,如果它加载了许多对象,则需要花费大量时间。因此,要默认停止加载时间,他们应该将其设置为延迟加载。

如果你在 ManyToOne 中使用 lazyfetch,当你执行一个查询时,你必须使用 join,该查询获取多端中的所有模型

最新更新