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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27519399/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 04:29:56  来源:igfitidea点击:

Why is the JPA FetchType EAGER by default for the @ManyToOne relationship?

javahibernatejpaormhibernate-mapping

提问by vatsal mevada

I came to notice in Hibernate source code that default FetchType for ManyToOne mapping is EAGER. Whereas for OnetoMany mapping default load type is Lazy. What is the specific reason behind this?

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

回答by Ankur Singhal

From the JPA 2.0 spec, the defaults are like so:

JPA 2.0 规范来看,默认值是这样的:

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

And in hibernate, all is Lazy

而在休眠状态下,一切都是懒惰的

From 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 对集合使用惰性选择获取,对单值关联使用惰性代理获取。这些默认值对大多数应用程序中的大多数关联都有意义。

To answer your question, Hibernate is an implementation of the JPA standard. Hibernate has its own quirks of operation, but as per the Hibernate docs

为了回答您的问题,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.

So Hibernate will always load any object using a lazy fetching strategy, no matter what type of relationship you have declared.

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

JPA Specassumes that in general most of the applications will require the singleton relations by default be eager, whereas multi value relations by default be lazy.

JPA Spec假设通常大多数应用程序默认情况下需要单例关系是eager的,而默认情况下多值关系是lazy。

Refer herefor more

参考这里了解更多

回答by Paul

if you use lazyfetch in ManyToOne, you have to use join when you do a query which gets all the models in the many side

如果您在 ManyToOne 中使用lazyfetch,则在执行获取多方所有模型的查询时必须使用join

回答by Vlad Mihalcea

JPA gotcha

JPA 陷阱

The reason for setting those to EAGER was because the early JPA 1.0 designers assumed that enforcing JPA implementations to support dynamically initializing Proxies would be a very strong requirement. However, since without Proxies, performance would suffer tremendously, all providers support LAZY associations.

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

Avoid FetchType.EAGER

避免 FetchType.EAGER

Using the default EAGER fetching strategy for @ManyToOneand @OneToOneassociations is a terrible ideaas you can easily end up with N+1 query issues.

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

When using Hibernate, once an association is set to FetchType.EAGER, you can no longer fetch it lazily at query time. So, you are always going to fetch that relationship whether the current business use case needs it or not.

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

Use FetchType.LAZYby default

FetchType.LAZY默认使用

So, you are better off using FetchType.LAZYby default for all associations.

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

Unlike FetchType.EAGER, a FetchType.LAZYrelationship can be fetched eagerly at query time using a JOIN FETCHclause.

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

The only thing you need to be aware of is that you need to fetch a lazy association in the context of the currently running Persistence Context if you need to access the association after the JPA EntityManageris closed. Otherwise, you are going to get a LazyInitializationException

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

回答by Stanislav Bashkyrtsev

In Hibernate OneToOne and ManyToOne by default won't be lazy even if you explicitly set it to be lazy.

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

Example: there is an association Parent->Child. By default this means PARENT_IDcolumn is in CHILDtable. ORM doesn't know if your Parent actually has a Child or it's null. If there is a Child, then an object must be set as a field to Parent. If it's null, then ORM must set null. To find out if it's null or not ORM has to query CHILD table. Since a query is made anyway, it makes sense to return Child right away if it exists.

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

So to make MTO or OTO lazy you need to instruct ORM that Child always exists (by making it not-optional a.k.a. required a.k.a. not-null). Therefore ORM knows that it's always present and knows that it can set a proxy instead of Child.

因此,要使 MTO 或 OTO 变得懒惰,您需要指示 ORM Child 始终存在(通过使其非可选,又名必需,又名非空)。因此 ORM 知道它始终存在并且知道它可以设置代理而不是 Child。

Alternatively you can keep CHILD_ID column in PARENT table. Then if Child is null the value in the record will be null as well. But for that you need to add configuration options (like @JoinColumn), it's not a default.

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

回答by Mahesh Shimpi

If you look at it carefully, you will find that if the relationship ends with Manykeyword i.e. OneToMany, ManyToMany, it is Lazy. If it ends with Onei.e. ManyToOne, OneToOne, it is Eager. So the thing is if you have to load just one object it will fetch it very fast. But if it is loading many objects it will take a lot of time. So, to stop that loading time by default they should have set it to the Lazy loading.

仔细看,你会发现,如果关系以Many关键字 ie OneToMany,结尾ManyToMany,那就是 Lazy。如果以Oneie ManyToOne,结尾OneToOne,则为 Eager。所以问题是如果你只需要加载一个对象,它就会非常快地获取它。但是如果它正在加载许多对象,它将花费很多时间。因此,要在默认情况下停止加载时间,他们应该将其设置为延迟加载。