我在Hibernate源代码中注意到,ManyToOne映射的默认FetchType是EAGER。而OnetoMany映射的默认加载类型是Lazy。这背后的具体原因是什么?
答案 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
关键字(即OneToMany
,ManyToMany
)结束,那就是懒惰了。如果以One
结尾,即ManyToOne
,OneToOne
结尾,则为渴望。因此,如果您只需要加载一个对象,它将很快地获取它。但是,如果要加载许多对象,则将花费大量时间。因此,默认情况下,要停止该加载时间,他们应该将其设置为延迟加载。