为什么@ManyToOne关系默认为JPA FetchType EAGER?

问题描述 投票:11回答:4

我在Hibernate源代码中注意到,ManyToOne映射的默认FetchType是EAGER。而OnetoMany映射的默认加载类型是Lazy。这背后的具体原因是什么?

java hibernate jpa orm hibernate-mapping
4个回答
26
投票

根据JPA 2.0规范,默认值如下:

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假设通常大多数应用程序默认需要单例关系,而默认情况下多值关系是惰性的。

请参阅here了解更多信息


6
投票

将这些设置为EAGER的原因是因为早期的JPA 1.0设计者认为强制执行JPA实现以支持动态初始化代理将是一个非常强烈的要求。但是,由于没有Proxies,性能会受到很大影响,所有提供商都支持LAZY关联。

使用@ManyToOne@OneToOne关联的默认EAGER获取策略是a code smell

正如this article中所解释的,我建议您将所有关联设置为LAZY,并使用每个HQL / JPQL或Criteria查询中提供的JOIN FETCH指令。


1
投票

在Hibernate中,OneToOne和ManyToOne默认情况下不会延迟,即使您明确将其设置为惰性也是如此。

示例:有一个关联Parent-> Child。默认情况下,这意味着PARENT_ID列位于CHILD表中。 ORM不知道您的父母是否真的有孩子,或者它是否为空。如果有Child,则必须将对象设置为Parent的字段。如果它为null,则ORM必须设置为null。要确定它是否为null,ORM必须查询CHILD表。由于无论如何都要进行查询,如果存在,则立即返回Child是有意义的。

因此,要使MTO或OTO变得懒惰,您需要指示ORM,Child始终存在(通过使其不可选a.k.a.需要a.k.a. not-null)。因此,ORM知道它始终存在并且知道它可以设置代理而不是Child。

或者,您可以在PARENT表中保留CHILD_ID列。然后,如果Child为null,则记录中的值也将为null。但为此你需要添加配置选项(如@JoinColumn),它不是默认值。


0
投票

如果你在ManyToOne中使用lazyfetch,你必须在进行查询时使用连接,这样可以获得多方面的所有模型

© www.soinside.com 2019 - 2024. All rights reserved.