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

时间:2014-12-17 06:15:44

标签: java hibernate jpa orm hibernate-mapping

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

5 个答案:

答案 0 :(得分:26)

JPA 2.0 spe c,默认值如下:

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

休眠中,一切都是懒惰的

来自Hibernate Docs,

  

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

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

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了解更多

答案 1 :(得分:6)

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

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

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

答案 2 :(得分: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),这不是默认设置。

答案 3 :(得分:0)

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

答案 4 :(得分:0)

如果仔细看,您会发现如果关系以Many关键字(即OneToManyManyToMany)结束,那就是懒惰了。如果以One结尾,即ManyToOneOneToOne结尾,则为渴望。因此,如果您只需要加载一个对象,它将很快地获取它。但是,如果要加载许多对象,则将花费大量时间。因此,默认情况下,要停止该加载时间,他们应该将其设置为延迟加载。