609

I am a newbie to Java Persistence API and Hibernate.

What is the difference between FetchType.LAZY and FetchType.EAGER in Java Persistence API?

Jaumzera
  • 1,874
  • 21
  • 37
leon
  • 8,725
  • 18
  • 57
  • 73
  • 2
    EAGER loading of collections means that they are fetched fully at the time their parent is fetched. While EAGER loading, then all my child is fetched. The child is fetched in the PersistentSet and PersistentList (or PersistentBag), inside the Persistent Bag , it displayed as an Array List. Is it correct??.. – geetha Mar 01 '17 at 06:12

16 Answers16

1172

Sometimes you have two entities and there's a relationship between them. For example, you might have an entity called University and another entity called Student and a University might have many Students:

The University entity might have some basic properties such as id, name, address, etc. as well as a collection property called students that returns the list of students for a given university:

A university has many students

public class University {
   private String id;
   private String name;
   private String address;
   private List<Student> students;

   // setters and getters
}

Now when you load a University from the database, JPA loads its id, name, and address fields for you. But you have two options for how students should be loaded:

  1. To load it together with the rest of the fields (i.e. eagerly), or
  2. To load it on-demand (i.e. lazily) when you call the university's getStudents() method.

When a university has many students it is not efficient to load all of its students together with it, especially when they are not needed and in suchlike cases you can declare that you want students to be loaded when they are actually needed. This is called lazy loading.

Here's an example, where students is explicitly marked to be loaded eagerly:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

    @OneToMany(fetch = FetchType.EAGER)
    private List<Student> students;

    // etc.    
}

And here's an example where students is explicitly marked to be loaded lazily:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

    @OneToMany(fetch = FetchType.LAZY)
    private List<Student> students;

    // etc.
}
βξhrαng
  • 41,698
  • 21
  • 103
  • 145
  • 5
    @BehrangSaeedzadeh can you list some practical differences, or the advantages and disadvantages of each type of loading (other than the efficiency you mentioned). Why would one want to use eager loading? – ADTC Jul 18 '13 at 06:36
  • 85
    @ADTC In order for lazy loading to work, the JDBC session must still be open when the target entities want to be loaded into the memory by invoking the getter method (e.g. `getStudents()`), but sometimes this is not possible, because by the time this method is called, the session is already closed and the entity detached. Similarly, sometimes we have a client/server architecture (e.g. Swing client/JEE server) and the entities/DTOs are transferred over the wire to the client and again most often in these scenarios lazy loading won't work due to the way the entities are serialized over the wire. – TheFooProgrammer Jul 18 '13 at 13:30
  • 5
    I'd like to add some more info to this answer from my book - To save memory, Lazy loading is generally used for one to many and many to many relationships. For one to one, generally Eager is used. – Erran Morad May 10 '14 at 05:53
  • 3
    In lazy loading, when I call the `getStudents()` method for the first time, are the results cached? so that I could access those results faster next time? – JavaTechnical Jun 09 '14 at 13:30
  • 2
    @JavaTechnical depends if you enable the second level cache (enabled by default) – Ced Feb 27 '16 at 01:36
  • @BoratSagdiyev that is bad advice IMHO(the eager loading you mention I mean). Use lazy everywhere and in JQL, fetch eagerly when you need to. Why? well, I keep running into system that are loading 6 joins because ToOne's are all eager. In fact, I want the old hibernate lazy default back. You never know your use-cases ahead of time and one will need lazy and another eager...instead use lazy everywhere and when you need eager, create a query for it. – Dean Hiller Oct 08 '16 at 22:49
  • @BoratSagdiyev This more clearly states why you should never use EAGER... https://vladmihalcea.com/2014/12/15/eager-fetching-is-a-code-smell/ perfect read. – Dean Hiller Oct 08 '16 at 22:52
  • If you don't use eager, how/ when do you close the session? Jaws DB for instance only gives 10 connections on their free tier and slightly more on expensive paid tiers, do this too is an issue). Fortunately my use case- blockchain one to many blocks is well suited to eager – gcr Apr 15 '21 at 19:12
307

Basically,

LAZY = fetch when needed
EAGER = fetch immediately
unbeli
  • 26,619
  • 5
  • 51
  • 55
  • 18
    Very clear but only after reading @Behang's answer. Thank you for clear summary. :-) – Nabin May 22 '16 at 17:18
70

EAGER loading of collections means that they are fetched fully at the time their parent is fetched. So if you have Course and it has List<Student>, all the students are fetched from the database at the time the Course is fetched.

LAZY on the other hand means that the contents of the List are fetched only when you try to access them. For example, by calling course.getStudents().iterator(). Calling any access method on the List will initiate a call to the database to retrieve the elements. This is implemented by creating a Proxy around the List (or Set). So for your lazy collections, the concrete types are not ArrayList and HashSet, but PersistentSet and PersistentList (or PersistentBag)

Bozho
  • 554,002
  • 136
  • 1,025
  • 1,121
  • I used that concept in fetching the details of a child entity, but I can not see any difference between them. When I specify Eager fetch, It fetches everything and When I debug it, I see "Bean deferred" at the child entity. When I say `course.getStudents()`, it fires an SQL query( saw that on console). In Lazy fetch type also, same thing happens. So, What's is the difference?? – Neha Choudhary Jan 03 '13 at 03:59
  • eager collections are fetched when the owning entity is loaded. Lazy collections are fetched when you access them. If this is not the behaviour your saw, there was probably something wrong with your environment (e.g. running old versions of a class) – Bozho Jan 03 '13 at 06:54
  • 1
    @Bozho You specified lazy loading of collections only . Can a simple string field be lazy loaded? – vikiiii Sep 12 '13 at 04:25
  • No. You need to use a query or a different mapped entity to get a subset of the columns – Bozho Sep 13 '13 at 04:55
  • @Bozho, hey can you please answer this then if it's set on `fetchtype = LAZY` the default one even if try to get the collection with the getter hibernete throws an error telling me it can't evaluate – Все Едно Jul 09 '17 at 07:05
19

I may consider performance and memory utilization. One big difference is that EAGER fetch strategy allows to use fetched data object without session. Why?
All data is fetched when eager marked data in the object when session is connected. However, in case of lazy loading strategy, lazy loading marked object does not retrieve data if session is disconnected (after session.close() statement). All that can be made by hibernate proxy. Eager strategy lets data to be still available after closing session.

rtruszk
  • 3,868
  • 13
  • 33
  • 53
Kyung Hwan Min
  • 289
  • 3
  • 4
  • Yes and it crashed my app until I switched to eager. I suppose session management is an art and science itself but JawsDB gives 10 connections on free tier and not much more on paid tiers. – gcr Apr 15 '21 at 19:09
11

By default, for all collection and map objects the fetching rule is FetchType.LAZY and for other instances it follows the FetchType.EAGER policy.
In brief, @OneToMany and @ManyToMany relations does not fetch the related objects (collection and map) implicictly but the retrieval operation is cascaded through the field in @OneToOne and @ManyToOne ones.

(courtesy :- objectdbcom)

rtruszk
  • 3,868
  • 13
  • 33
  • 53
babai
  • 111
  • 1
  • 2
11

As per my knowledge both type of fetch depends your requirement.

FetchType.LAZY is on demand (i.e. when we required the data).

FetchType.EAGER is immediate (i.e. before our requirement comes we are unnecessarily fetching the record)

JDGuide
  • 5,759
  • 11
  • 39
  • 53
11

Both FetchType.LAZY and FetchType.EAGER are used to define the default fetch plan.

Unfortunately, you can only override the default fetch plan for LAZY fetching. EAGER fetching is less flexible and can lead to many performance issues.

My advice is to restrain the urge of making your associations EAGER because fetching is a query-time responsibility. So all your queries should use the fetch directive to only retrieve what's necessary for the current business case.

Vlad Mihalcea
  • 103,297
  • 39
  • 432
  • 788
  • 2
    *"EAGER fetching is less flexible and can lead to many performance issues."* ... A truer statement is "Using or not using EAGER fetching can lead to performance problems". In that particular case when a lazily initialized field is expensive to access AND infrequently used, lazy fetching will benefit performance. But, in the case when a variable is frequently used, lazy initialization can *actually degrade performance* by requiring more trips to the database than eager initialization. I would suggest applying FetchType correctly, not dogmatically. – scottb May 18 '17 at 18:38
  • Are you promoting your book here!!. But yes I feel it depends on the use case, and the object size being referred to in the cardinality relationship. – John Doe May 25 '18 at 09:44
8

The Lazy Fetch type is by default selected by Hibernate unless you explicitly mark Eager Fetch type. To be more accurate and concise, difference can be stated as below.

FetchType.LAZY = This does not load the relationships unless you invoke it via the getter method.

FetchType.EAGER = This loads all the relationships.

Pros and Cons of these two fetch types.

Lazy initialization improves performance by avoiding unnecessary computation and reduce memory requirements.

Eager initialization takes more memory consumption and processing speed is slow.

Having said that, depends on the situation either one of these initialization can be used.

Dulith De Costa
  • 8,429
  • 1
  • 53
  • 43
  • 1
    The statement that it "does not load the relationships unless you invoke it via the getter method" is important to note, and also a pretty retarded design decision in my opininion… I just encountered a case where I assumed it would fetch it *upon access* and it didn't, because I didn't excplicitly call a getter function for it. By the way, what constitutes a "getter" function? Will JPA defer loading the property until a function called `getMember` is called that exactly matches the member's name pattern? – ToVine Jul 24 '18 at 16:02
6

From the Javadoc:

The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed.

E.g., eager is more proactive than lazy. Lazy only happens on first use (if the provider takes the hint), whereas with eager things (may) get pre-fetched.

T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • 1
    what do you mean by "first use"? – leon Jun 07 '10 at 15:43
  • 1
    @leon: Say you have an entity with an eager field and a lazy field. When you get the entity, the eager field will have been loaded from the DB by the time you receive the entity reference, but the lazy field may not have been. It would be fetched only when you tried to *access* the field via its accessor. – T.J. Crowder Jun 07 '10 at 15:56
  • @T.J. Crowder, what's the default when no fetchtype defined ? – Mahmoud Saleh Nov 05 '12 at 15:42
  • @MahmoudSaleh: I have no idea. It probably varies based on something. I haven't used JPA in a real project so I haven't gotten into the guts of it. – T.J. Crowder Nov 05 '12 at 15:44
  • 2
    @MahmoudS: Default fetchtypes: OneToMany: LAZY, ManyToOne: EAGER, ManyToMany: LAZY, OneToOne: EAGER, Columns : EAGER – Markus Pscheidt Apr 21 '15 at 10:16
5

The main difference between the two types of fetching is a moment when data gets loaded into a memory.
I have attached 2 photos to help you understand this.

Eager fetch
 Eager fetch

Lazy fetch Lazy fetch

Ali Yeganeh
  • 557
  • 8
  • 13
4

I want to add this note to what said above.

Suppose you are using Spring (MVC and Data) with this simple architect:

Controller <-> Service <-> Repository

And you want to return some data to the front-end, if you are using FetchType.LAZY, you will get an exception after you return data to the controller method since the session is closed in the Service so the JSON Mapper Object can't get the data.

There is three common options to solve this problem, depends on the design, performance and the developer:

  1. The easiest one is to use FetchType.EAGER, So that the session will still alive at the controller method, but this method will impact the performance.
  2. Anti-patterns solutions, to make the session live until the execution ends, it is make a huge performance issue in the system.
  3. The best practice is to use FetchType.LAZY with mapper like MapStruct to transfer data from Entity to another data object DTO and then send it back to the controller, so there is no exception if the session closed.
Ebraheem Alrabeea
  • 1,453
  • 3
  • 17
  • 31
3

Book.java

        import java.io.Serializable;
        import javax.persistence.Column;
        import javax.persistence.Entity;
        import javax.persistence.GeneratedValue;
        import javax.persistence.GenerationType;
        import javax.persistence.Id;
        import javax.persistence.ManyToOne;
        import javax.persistence.Table;

        @Entity
        @Table(name="Books")
        public class Books implements Serializable{

        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @Column(name="book_id")
        private int id;
        @Column(name="book_name")
        private String name;

        @Column(name="author_name")
        private String authorName;

        @ManyToOne
        Subject subject;

        public Subject getSubject() {
            return subject;
        }
        public void setSubject(Subject subject) {
            this.subject = subject;
        }

        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getAuthorName() {
            return authorName;
        }
        public void setAuthorName(String authorName) {
            this.authorName = authorName;
        }

        }

Subject.java

    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue; 
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.OneToMany;
    import javax.persistence.Table;

    @Entity
    @Table(name="Subject")
    public class Subject implements Serializable{

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="subject_id")
    private int id;
    @Column(name="subject_name")
    private String name;
    /**
    Observe carefully i have mentioned fetchType.EAGER. By default its is fetchType.LAZY for @OneToMany i have mentioned it but not required. Check the Output by changing it to fetchType.EAGER
    */

    @OneToMany(mappedBy="subject",cascade=CascadeType.ALL,fetch=FetchType.LAZY,
orphanRemoval=true)
    List<Books> listBooks=new ArrayList<Books>();

    public List<Books> getListBooks() {
        return listBooks;
    }
    public void setListBooks(List<Books> listBooks) {
        this.listBooks = listBooks;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    }

HibernateUtil.java

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {

 private static SessionFactory sessionFactory ;
 static {
    Configuration configuration = new Configuration();
    configuration.addAnnotatedClass (Com.OneToMany.Books.class);
    configuration.addAnnotatedClass (Com.OneToMany.Subject.class);
    configuration.setProperty("connection.driver_class","com.mysql.jdbc.Driver");
    configuration.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/hibernate");                                
    configuration.setProperty("hibernate.connection.username", "root");     
    configuration.setProperty("hibernate.connection.password", "root");
    configuration.setProperty("dialect", "org.hibernate.dialect.MySQLDialect");
    configuration.setProperty("hibernate.hbm2ddl.auto", "update");
    configuration.setProperty("hibernate.show_sql", "true");
    configuration.setProperty(" hibernate.connection.pool_size", "10");
    configuration.setProperty(" hibernate.cache.use_second_level_cache", "true");
    configuration.setProperty(" hibernate.cache.use_query_cache", "true");
    configuration.setProperty(" cache.provider_class", "org.hibernate.cache.EhCacheProvider");
    configuration.setProperty("hibernate.cache.region.factory_class" ,"org.hibernate.cache.ehcache.EhCacheRegionFactory");

   // configuration
    StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
    sessionFactory = configuration.buildSessionFactory(builder.build());
 }
public static SessionFactory getSessionFactory() {
    return sessionFactory;
}
} 

Main.java

    import org.hibernate.Session;
    import org.hibernate.SessionFactory;

    public class Main {

    public static void main(String[] args) {
        SessionFactory factory=HibernateUtil.getSessionFactory();
        save(factory);
        retrieve(factory);

    }

     private static void retrieve(SessionFactory factory) {
        Session session=factory.openSession();
        try{
            session.getTransaction().begin();
            Subject subject=(Subject)session.get(Subject.class, 1);
            System.out.println("subject associated collection is loading lazily as @OneToMany is lazy loaded");

            Books books=(Books)session.get(Books.class, 1);
            System.out.println("books associated collection is loading eagerly as by default @ManyToOne is Eagerly loaded");
            /*Books b1=(Books)session.get(Books.class, new Integer(1));

            Subject sub=session.get(Subject.class, 1);
            sub.getListBooks().remove(b1);
            session.save(sub);
            session.getTransaction().commit();*/
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            session.close();
        }

        }

       private static void save(SessionFactory factory){
        Subject subject=new Subject();
        subject.setName("C++");

        Books books=new Books();
        books.setAuthorName("Bala");
        books.setName("C++ Book");
        books.setSubject(subject);

        subject.getListBooks().add(books);
        Session session=factory.openSession();
        try{
        session.beginTransaction();

        session.save(subject);

        session.getTransaction().commit();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            session.close();
        }
    }

    }

Check the retrieve() method of Main.java. When we get Subject, then its collection listBooks, annotated with @OneToMany, will be loaded lazily. But, on the other hand, Books related association of collection subject, annotated with @ManyToOne, loads eargerly (by [default][1] for @ManyToOne, fetchType=EAGER). We can change the behaviour by placing fetchType.EAGER on @OneToMany Subject.java or fetchType.LAZY on @ManyToOne in Books.java.

Khalil M
  • 1,432
  • 2
  • 17
  • 33
Deepak
  • 1,532
  • 1
  • 16
  • 20
1

public enum FetchType extends java.lang.Enum Defines strategies for fetching data from the database. The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed. The implementation is permitted to eagerly fetch data for which the LAZY strategy hint has been specified. Example: @Basic(fetch=LAZY) protected String getName() { return name; }

Source

Anas Lachheb
  • 411
  • 4
  • 16
0

@drop-shadow if you're using Hibernate, you can call Hibernate.initialize() when you invoke the getStudents() method:

Public class UniversityDaoImpl extends GenericDaoHibernate<University, Integer> implements UniversityDao {
    //...
    @Override
    public University get(final Integer id) {
        Query query = getQuery("from University u where idUniversity=:id").setParameter("id", id).setMaxResults(1).setFetchSize(1);
        University university = (University) query.uniqueResult();
        ***Hibernate.initialize(university.getStudents());***
        return university;
    }
    //...
}
rtruszk
  • 3,868
  • 13
  • 33
  • 53
Jules0707
  • 555
  • 4
  • 3
0

LAZY: It fetches the child entities lazily i.e at the time of fetching parent entity it just fetches proxy(created by cglib or any other utility) of the child entities and when you access any property of child entity then it is actually fetched by hibernate.

EAGER: it fetches the child entities along with parent.

For better understanding go to Jboss documentation or you can use hibernate.show_sql=true for your app and check the queries issued by the hibernate.

marc_s
  • 675,133
  • 158
  • 1,253
  • 1,388
user1157635
  • 174
  • 1
  • 11
0

JOIN is the big deal

Take it in easy way :

assume we have a class called User and another class called an Address and suppose each user have one or more addresses that mean relationship (one-to-many) here if you execute :

FetchType.LAZY execute sql command like without join :

SELECT * FROM users 

FetchType.EAGER execute sql command like within join :

SELECT * FROM users u join address a on a.user_id = u.user_id

Note : the above queries just for clarify image for you but Hibernate framework in realty execute similar queries of above quires .

Which Fetch Types is Better?

  • Since Eager fetching loads ALL relationships automatically, It's a big performance hog
  • Lazy fetching doesn't load any relationships unless told to, which leads to better performance
  • Eager fetching makes for easier programming, since less code is required
  • Lazy loading could lead to bugs (exceptions) If the entire system Isn't properly tested
  • All things considered, you should still prefer Lazy loading over Eager, as it's more performant

If you are using Spring Boot Framework so going to application.properties file and add the below command to know what exactly going on .

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
Abd Abughazaleh
  • 1,259
  • 9
  • 28