Hi, in this post, we will understand the concept of LAZY and EAGER loading in Hibernate.

Let us assume that we have an entity Employee and another entity Sale in our application. Each employee may have multiple sales.
Now, when we try to load employee object, two things can happen:

  1. When employee is loaded, none of sales are loaded ( lazy loading )
  2. When employee is loaded, all the sales are loaded as well ( eager loading )

Let us create a project to understand the two types of loading. We will be creating Maven based project, so I assume your Eclipse has Maven configured. If not, install it from Help -> Eclipse Marketplace

  1. Start Eclipse and create a new Java project. Give it name HibernateLoading
  2. Right click on the project -> Configure -> Convert to Maven project
  3. Remove the src folder in it.
  4. Right click on your project -> New -> Source Folder
  5. Give it name src/main/java
  6. Similarly, create one more source folder: src/main/resources
  7. Now create following packages inside the src/main/java folder:
    com.loading.entity
    com.loading.utility
    com.loading.main
  8. Next, create the two entity classes: Employee and Sale inside the com.loading.entity package.
    Employee.java

    package com.loading.entity;
    import java.util.List;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.Id;
    import javax.persistence.OneToMany;
    import javax.persistence.Table;
    @Entity
    @Table(name="employees")
    public class Employee {
       @Id
       @Column(name="id")
       private int id;
     
       private String name;
       private String gender;
     
       @OneToMany(fetch=FetchType.LAZY, mappedBy="employee")
       private List<Sale> sales;
     
       public int getEmployeeId() {
          return id;
       }
       public void setEmployeeId(int id) {
          this.id = id;
       }
       public String getName() {
          return name;
       }
       public void setName(String name) {
          this.name = name;
       }
       public String getGender() {
          return gender;
       }
       public void setGender(String gender) {
          this.gender = gender;
       }
       public List<Sale> getSales() {
          return sales;
       }
       public void setSales(List<Sale> sales) {
          this.sales = sales;
       }
    }

    Sale.java

    package com.loading.entity;
    import java.util.Date;
    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="sales")
    public class Sale {
       @Id
       @GeneratedValue(strategy=GenerationType.IDENTITY)
       @Column(name="id")
       private int id;
    
       @ManyToOne
       private Employee employee;
    
       private double amount;
    
       @Column(name="item_name", length=100)
       private String itemName;
    
       @Column(name="created_at")
       private Date createdAt;
       public int getId() {
          return id;
       }
       public Employee getEmployee() {
          return employee;
       }
       public double getAmount() {
          return amount;
       }
       public String getItemName() {
          return itemName;
       }
       public Date getCreatedAt() {
          return createdAt;
       }
       public void setId(int id) {
          this.id = id;
       }
       public void setEmployee(Employee employee) {
          this.employee = employee;
       }
       public void setAmount(double amount) {
          this.amount = amount;
       }
       public void setItemName(String itemName) {
          this.itemName = itemName;
       }
       public void setCreatedAt(Date createdAt) {
          this.createdAt = createdAt;
       }
    }
  9. Next we create the hibernate configuration file in src/main/java folder. Here is the code: hibernate.cfg.xml
    <?xml version='1.0' encoding='utf-8'?>
    <!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
      <session-factory>
         <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
         <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_loading</property>
         <property name="hibernate.connection.username">h_user</property>
         <property name="hibernate.connection.password">h_password</property>
         <property name="hibernate.connection.pool_size">10</property>
         <property name="show_sql">true</property>
         <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
         <property name="hibernate.hbm2ddl.auto">create</property>
         <property name="hibernate.hbm2ddl.import_files">import.sql</property>
    
         <!-- Mapping classes -->
         <mapping class="com.loading.entity.Employee"/>
         <mapping class="com.loading.entity.Sale"/>
     
       </session-factory>
    </hibernate-configuration>

    *Note: In the configuration, we set the show_sql property to true because we want to see the number of queries Hibernate is executing in the background for LAZY and EAGER fetch type.

  10. Let us create import.sql file in src/main/resources folder to automatically insert some sample data in the tables.  Hibernate will execute the queries in this file once when database tables are created. We need to make sure that each sql query must be in a single line. Here are the queries in the file:
    insert into employees(id, name, gender) values(1, 'a', 'male');
    insert into employees(id, name, gender) values(2, 'b', 'female');
    insert into employees(id, name, gender) values(3, 'c', 'male');
    insert into employees(id, name, gender) values(4, 'd', 'female');
    
    insert into sales(employee_id, amount, item_name, created_at) values(1, 5000, 'Adidas Shoe', '2015-3-10');
    insert into sales(employee_id, amount, item_name, created_at) values(1, 3000, 'Rayban Aviator', '2015-3-10');
    insert into sales(employee_id, amount, item_name, created_at) values(2, 1500, 'Sandisk Memory Card', '2015-3-10');
    insert into sales(employee_id, amount, item_name, created_at) values(1, 4000, 'Nike Shoe', '2015-3-10');
    insert into sales(employee_id, amount, item_name, created_at) values(3, 10000, 'Samsung LCD', '2015-3-10');
    insert into sales(employee_id, amount, item_name, created_at) values(4, 30000, 'Nexus 6', '2015-3-10');
    insert into sales(employee_id, amount, item_name, created_at) values(4, 32000, 'Samsung galaxy S5', '2015-3-10');

    We already specified this file in hibernate.cfg.xml in the line:

    <property name="hibernate.hbm2ddl.import_files">import.sql</property>
  11. Now, we will create the HibernateUtil class to load this configuration. Create the file HibernateUtil.java inside com.loading.utility package with following code:
    package com.loading.utility;
    
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.AnnotationConfiguration;
    
    public class HibernateUtil {
        private static final SessionFactory sessionFactory;
        private static ServiceRegistry serviceRegistry;
        static {
            try {
                Configuration configuration = new Configuration();
                configuration.configure();
                serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
                sessionFactory = configuration.buildSessionFactory(serviceRegistry);
            } catch (Throwable ex) {
              System.err.println("Initial SessionFactory creation failed." + ex);
              throw new ExceptionInInitializerError(ex);
            }
        }
    
        public static SessionFactory getSessionFactory() {
           return sessionFactory;
        }
    }
  12. Lastly, here is the pom.xml file which should be placed in the root folder i.e. HibernateLoading folder.
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <groupId>HibernateLoading</groupId>
     <artifactId>Example</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <packaging>jar</packaging>
     
     <properties>
        <hibernate.version>4.2.0.Final</hibernate.version>
        <slf4j.version>1.6.1</slf4j.version>
        <cglib.version>2.2</cglib.version> 
        <mysql.version>5.1.24</mysql.version>
     </properties>
     
     <dependencies>
      
        <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-core</artifactId>
          <version>${hibernate.version}</version>
          <type>jar</type>
          <scope>compile</scope>
       </dependency>
       <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-annotations</artifactId>
          <version>3.5.6-Final</version>
          <type>jar</type>
          <scope>compile</scope>
       </dependency> 
       <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-validator</artifactId>
          <version>${hibernate.version}</version>
          <type>jar</type>
          <scope>compile</scope>
       </dependency> 
       <dependency>
          <groupId>javax.persistence</groupId>
          <artifactId>persistence-api</artifactId>
          <version>1.0</version>
          <type>jar</type>
          <scope>compile</scope>
       </dependency>
       <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>${mysql.version}</version>
          <scope>runtime</scope>
       </dependency>
       <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
          <version>${slf4j.version}</version>
          <type>jar</type>
          <scope>compile</scope>
       </dependency>
       <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>${slf4j.version}</version>
          <type>jar</type>
          <scope>compile</scope>
       </dependency>
       <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>jcl-over-slf4j</artifactId>
          <version>${slf4j.version}</version>
          <type>jar</type>
          <scope>compile</scope>
       </dependency>
       <dependency>
          <groupId>cglib</groupId>
          <artifactId>cglib-nodep</artifactId>
          <version>${cglib.version}</version>
          <type>jar</type>
          <scope>compile</scope>
       </dependency>
       <dependency>
          <groupId>javassist</groupId>
          <artifactId>javassist</artifactId>
          <version>3.12.1.GA</version>
       </dependency> 
     </dependencies>
    </project>
  13. Let us now test our code. Create the file Test.java in com.loading.main package and add following code:
    package com.loading.main;
    
    import java.util.List;
    import org.hibernate.Query;
    import org.hibernate.Session;
    import com.loading.entity.Employee;
    import com.loading.utility.HibernateUtil;
    
    public class Test {
       public static void main(String[] args) {
          Session session = HibernateUtil.getSessionFactory().openSession();
     
          Query query = session.createQuery("from Employee");
     
          @SuppressWarnings("unchecked")
          List<Employee> employees = (List<Employee>)query.list();
     
          if(employees!=null && !employees.isEmpty()){
     
             for(Employee employee : employees){
                 System.out.println(employee.getName() + " is a " + employee.getGender());
             }
         }
         else {
            System.out.println("No employees found...");
         }
     }
    }
  14. Now execute this file. The output on the console should be similar to this:
    Hibernate: select employee0_.id as id1_0_, employee0_.gender as gender2_0_, employee0_.name as name3_0_ from employees employee0_
    a is a male
    b is a female
    c is a male
    d is a female

    You can see only one query is executed by Hibernate to load employees. No sales are loaded for employees here.
    Now edit the Employee.java file and change:

    @OneToMany(fetch=FetchType.LAZY, mappedBy="employee")

    To

    @OneToMany(fetch=FetchType.Eager, mappedBy="employee")

    Again execute the program. The output should be similar to this:

    Hibernate: select employee0_.id as id1_0_, employee0_.gender as gender2_0_, employee0_.name as name3_0_ from employees employee0_
    Hibernate: select sales0_.employee_id as employee5_0_1_, sales0_.id as id1_1_1_, sales0_.id as id1_1_0_, sales0_.amount as amount2_1_0_, sales0_.created_at as created3_1_0_, sales0_.employee_id as employee5_1_0_, sales0_.item_name as item4_1_0_ from sales sales0_ where sales0_.employee_id=?
    Hibernate: select sales0_.employee_id as employee5_0_1_, sales0_.id as id1_1_1_, sales0_.id as id1_1_0_, sales0_.amount as amount2_1_0_, sales0_.created_at as created3_1_0_, sales0_.employee_id as employee5_1_0_, sales0_.item_name as item4_1_0_ from sales sales0_ where sales0_.employee_id=?
    Hibernate: select sales0_.employee_id as employee5_0_1_, sales0_.id as id1_1_1_, sales0_.id as id1_1_0_, sales0_.amount as amount2_1_0_, sales0_.created_at as created3_1_0_, sales0_.employee_id as employee5_1_0_, sales0_.item_name as item4_1_0_ from sales sales0_ where sales0_.employee_id=?
    Hibernate: select sales0_.employee_id as employee5_0_1_, sales0_.id as id1_1_1_, sales0_.id as id1_1_0_, sales0_.amount as amount2_1_0_, sales0_.created_at as created3_1_0_, sales0_.employee_id as employee5_1_0_, sales0_.item_name as item4_1_0_ from sales sales0_ where sales0_.employee_id=?
    a is a male
    b is a female
    c is a male
    d is a female

    This time, four extra queries are executed by Hibernate to load sales for four different employees.

Whenever you want that child data should always be loaded with parent object, use EAGER loading, but this requires more memory as lot of objects will be fetched from database.
LAZY loading will pick child objects only when they are required i.e. getter methods are called. This will require less memory and is recommended when there are large number of child objects per parent object.

Download the complete project from the link below

HibernateLoading