I came to notice that he default FetchType
for the @ManyToOne
mapping is EAGER
i JPA and Hibernate, whereas, for the @OneToMany
mapping, the default FetchType
is LAZY
.
What is the specific reason behind this?
I came to notice that he default FetchType
for the @ManyToOne
mapping is EAGER
i JPA and Hibernate, whereas, for the @OneToMany
mapping, the default FetchType
is LAZY
.
What is the specific reason behind this?
From the JPA 2.0 spec, the defaults are like so:
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.
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
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.
JPA Spec assumes that in general most of the applications will require the singleton relations by default be eager, whereas multi value relations by default be lazy.
Refer here for more
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.
FetchType.EAGER
Using the default EAGER fetching strategy for @ManyToOne
and @OneToOne
associations is a terrible idea as you can easily end up with N+1 query issues.
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.
FetchType.LAZY
by defaultSo, you are better off using FetchType.LAZY
by default for all associations.
Unlike FetchType.EAGER
, a FetchType.LAZY
relationship can be fetched eagerly at query time using a JOIN FETCH
clause.
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 EntityManager
is closed. Otherwise, you are going to get a LazyInitializationException
In Hibernate OneToOne and ManyToOne by default won't be lazy even if you explicitly set it to be lazy.
Example: there is an association Parent->Child. By default this means PARENT_ID
column is in CHILD
table. 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.
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.
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.
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
If you look at it carefully, you will find that if the relationship ends with Many
keyword i.e. OneToMany
, ManyToMany
, it is Lazy. If it ends with One
i.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.