17

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?

Vlad Mihalcea
  • 103,297
  • 39
  • 432
  • 788
vatsal mevada
  • 3,808
  • 5
  • 28
  • 57

5 Answers5

33

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

Ankur Singhal
  • 23,626
  • 10
  • 70
  • 108
  • 1
    Can you provide the link to the documentation from where you have copied the quoted text? – RAS Dec 17 '14 at 06:26
  • @RAS refer [this](https://docs.jboss.org/hibernate/orm/3.6/reference/en-US/html/performance.html#performance-fetching-lazy) – Ankur Singhal Dec 17 '14 at 06:34
  • 1
    "So Hibernate will always load any object using a lazy fetching strategy, no matter what type of relationship you have declared." Incorrect as Hibernate is loading using EAGER strategy in code where I have used ManyToOne mapping. And also in hibernate source default Fetch type is set to EAGER. – vatsal mevada Dec 17 '14 at 06:37
  • 1
    @vatsalmevada are you using Hibernate or JPA – Ankur Singhal Dec 17 '14 at 06:38
  • 1
    Sorry I am using JPA annotations.. If I use hibernate mapping files then it will do LAZY fetch by default? – vatsal mevada Dec 17 '14 at 06:51
  • 1
    @vatsalmevada yes that is what i explained in my answer, JPA and Hibernate behaves differently. JPA is just the implementation – Ankur Singhal Dec 17 '14 at 06:54
  • 1
    i.e Hibernate doesn't follow the JPA spec then? aka incompatibility. – Neil Stockton Aug 01 '17 at 13:20
  • what about A -> B -> C. if I get C, B will be eager in C object. will that B contains A too? or only eager upto one level? – P Satish Patro Sep 05 '19 at 11:13
15

JPA gotcha

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.

Avoid 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.

Use FetchType.LAZY by default

So, 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

Vlad Mihalcea
  • 103,297
  • 39
  • 432
  • 788
  • It is also worth noting that @OneToOne in Hibernate is always Eager unless the association is marked as optional=false. http://stackoverflow.com/questions/1444227/making-a-onetoone-relation-lazy – Alan Hay Dec 17 '14 at 12:50
  • except that many JPA providers don't use "proxies" for single-valued relations. – Neil Stockton Aug 01 '17 at 12:58
1

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.

Stanislav Bashkyrtsev
  • 11,403
  • 7
  • 33
  • 38
0

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

Paul
  • 123
  • 1
  • 13
0

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.

cokeman19
  • 2,348
  • 23
  • 39