Hibernate Lazy vs Eager loading Example

In this tutorial, we will see JPA/Hibernate Lazy vs Eager loading Example using Spring Boot and Oracle.

Important points about Hibernate Lazy and Eager loading.

We use the fetch type(Lazy and Eager loading) for association mapping –  For example, for below association mapping we can define fetch type.

  • OneToOne mapping.
  • OneToMany mapping.
  • ManyToOne mapping
  • ManyToMany mapping
  • ElementCollection(used for embeddable objects). See an example about @ElementCollection.

Lazy loading(fetch = FetchType.LAZY) –  We can define fetch type for OneToMany mapping as @OneToMany(fetch = FetchType.LAZY). The FetchType.LAZY loads child entity lazily or when it needed(on demand). What does it mean?

Consider we have two entity Book.java and Story.java which are mapped in OneToMany relationships. One Book can have multiple stories.

@Entity
public class Book {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int bookId;

	@Column(name = "book_name")
	private String bookName;

	@OneToMany(fetch = FetchType.LAZY)
	@JoinColumn(name = "book_id", referencedColumnName = "bookId")
	private List<Story> storyList = new ArrayList<>();

   //getter & setter

}

Story.java

@Entity
public class Story {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int storyId;

	@Column(name = "story_name")
	private String storyName;

   //getter & setter

}

When we load a Book entity from the database, Hibernate will not load Story entities unless we will not do book.getStoryList();.  Since we have  @OneToMany(fetch = FetchType.LAZY) with storyList field.

Eager loading for Hibernate Eager vs Lazy loading Example and also we will later query.

Eager loading(fetch = FetchType.EAGER) – When we define fetch type is EAGER it will load child entities along with parent entity. For example, consider one Book has five stories, if we do @OneToMany(fetch = FetchType.EAGER) we will have five story entities along with Book entity. We will see later in details.

@Entity
public class Book {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int bookId;

	@Column(name = "book_name")
	private String bookName;

	@OneToMany(fetch = FetchType.EAGER)
	@JoinColumn(name = "book_id", referencedColumnName = "bookId")
	private List<Story> storyList = new ArrayList<>();

//gette & setter

}

Default Fetch type in case of the below annotations.

@OneToOne – Default fetch type is EAGER
@OneToMany – Default fetch type is LAZY.
@ManyToOne – Default fetch type is EAGER.
@ManyToMany – Default fetch type is LAZY.
@ElementCollection – Default fetch type is EAGER.


Query Creation in case of Lazy and Eager loading.

In the case of fetch = FetchType.LAZY if we try to fetch Book entity, two separate queries will get generated. One for Book entity and another for Story entities. 

For fetch = FetchType.EAGER if we try to fetch Book entity, Only one query will get generated with JOIN. We will see in details at the end of the post.

When to use lazy loading and Eager loading.

Consider we have Book and Story entity in OneToMany relationship and One Book contains a hundred or thousands Story entity. In this case, defining fetch = FetchType.EAGER might not a good idea. It will fetch all child(Story) entities along with Book entity. This might impact performance. We can define fetch type Lazy when the possibility of child entities records are more in number.

For OneToOne and ManyToOne default load type is Eager most of the time it’s better to leave it Eager only since we have OneToOne association.

Summary – There is no straight forward rule to decide when to use Lazy or Eager fetch Type. After knowing the application and entities and data(number of the possible child entities) we can decide to use Lazy or Eager fetch Type.

LazyInitializationException – Failed to lazily initialize a collection of role could not initialize proxy – no Session.

When you working with association mapping you may encounter LazyInitializationException could not initialize proxy – no Session. This exception comes when two entities are in association mapping with fetch= FetchType.LAZY and we try to get child entity from the parent entity after the session gets closed. 

We have a separate and detailed post, how to fix this using a different approach.

we will see JPA/Hibernate Eager vs Lazy Fetch Type Example using Spring Boot and Oracle.

Hibernate Lazy vs Eager loading Example Using Spring Boot and Oracle.

Open eclipse and create maven project, Don’t forget to check ‘Create a simple project (skip)’click on next. Fill all details(GroupId – fetchtype, ArtifactId – fetchtype and name – fetchtype) and click on finish. Keep packaging as the jar.


Modify the pom.xml with the below code.

<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>fetchtype</groupId>
	<artifactId>fetchtype</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>fetchtype</name>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.2.RELEASE</version>
	</parent>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>

		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>com.oracle</groupId>
			<artifactId>ojdbc6</artifactId>
			<version>11.2.0.3</version>
		</dependency>

	</dependencies>

	<build>
		<finalName>${project.artifactId}</finalName>
		<plugins>

			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<fork>true</fork>
					<executable>C:\Program Files\Java\jdk1.8.0_131\bin\javac.exe</executable>
				</configuration>
			</plugin>


		</plugins>
	</build>
</project>

Note – In pom.xml we have defined javac.exe path in configuration tag. You need to change accordingly i.e where you have installed JDK.

If you see any error for oracle dependency then follow these steps.

Define entity class i.e Book.java and Story.java.

Book.java

package com.onetoonehibernatejpa.entity;

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.JoinColumn;
import javax.persistence.OneToMany;

@Entity
public class Book {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int bookId;

	@Column(name = "book_name")
	private String bookName;

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JoinColumn(name = "book_id", referencedColumnName = "bookId")
	private List<Story> storyList = new ArrayList<>();

	public int getBookId() {
		return bookId;
	}

	public void setBookId(int bookId) {
		this.bookId = bookId;
	}

	public String getBookName() {
		return bookName;
	}

	public void setBookName(String bookName) {
		this.bookName = bookName;
	}

	public List<Story> getStoryList() {
		return storyList;
	}

	public void setStoryList(List<Story> storyList) {
		this.storyList = storyList;
	}

}

Story.java

package com.hibernatejpa.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Story {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int storyId;

	@Column(name = "story_name")
	private String storyName;

	public int getStoryId() {
		return storyId;
	}

	public void setStoryId(int storyId) {
		this.storyId = storyId;
	}

	public String getStoryName() {
		return storyName;
	}

	public void setStoryName(String storyName) {
		this.storyName = storyName;
	}

}

Define the repository interface extending CrudRepository.

BookRepository.java

package com.hibernatejpa.repository;

import java.io.Serializable;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.hibernatejpa.entity.Book;
@Repository
public interface BookRepository extends CrudRepository<Book,Serializable> {
	public Book findByBookId(int bookId);
}

Define service interface i.e BookService.java

package com.onetoonehibernatejpa.service;

import org.springframework.stereotype.Component;

import com.onetoonehibernatejpa.entity.Book;

@Component
public interface BookService {
	public Book saveBook(Book book);
	public Book findByBookId(int bookId);// Optional
}

Define service implementation class.

BookServiceImpl.java


package com.onetoonehibernatejpa.impl;

import java.util.Optional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.onetoonehibernatejpa.entity.Book;
import com.onetoonehibernatejpa.repository.BookRepository;
import com.onetoonehibernatejpa.repository.StoryRepository;
import com.onetoonehibernatejpa.service.BookService;

@Service("bookServiceImpl")
public class BookServiceImpl implements BookService {

	@Autowired
	private BookRepository bookRepository;

	@Autowired
	private StoryRepository storyRepository;

	@PersistenceContext
	private EntityManager entityManager;

	@Transactional
	public Book saveBook(Book book) {
		book = bookRepository.save(book);
		return book;
	}

	public Book findByBookId(int bookId) {
		Optional<Book> bookResponse = bookRepository.findById(bookId);
		Book book = bookResponse.get();
		return book;
	}
}

Note – See here more about @Component, @Controller, @Service and @Repository annotations here.

Define the controller class or endpoint.

BookController.java

package com.onetoonehibernatejpa.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.onetoonehibernatejpa.entity.Book;
import com.onetoonehibernatejpa.service.BookService;
 
@RestController
@RequestMapping(value = "/book")
public class BookController {
	
	@Autowired
	private BookService bookService;
	
	
	@RequestMapping(value = "/savebook",method = RequestMethod.POST)
	@ResponseBody
    public Book saveBook(@RequestBody Book book) {
		Book bookResponse = bookService.saveBook(book);
		return bookResponse;
	}
	
	@RequestMapping(value = "/{bookId}",method = RequestMethod.GET)
    @ResponseBody
    public Book getBookDetails(@PathVariable int bookId) {
		Book bookResponse = bookService.findByBookId(bookId);
		
		return bookResponse;
	}
	
	
}

Note – See more details about @Controller and RestController here.

Define the JpaConfig.java

package com.hibernatejpa.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration
@EnableJpaRepositories(basePackages = "com.hibernatejpa.repository")
public class JpaConfig {

}

Step 12 – Define the SpringMain.java

package com.hibernatejpa.main;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages="com.hibernatejpa.*")
@EntityScan("com.hibernatejpa.*")
public class SpringMain {
	public static void main(String[] args) {

        SpringApplication.run(SpringMain.class, args);
    }

}

And finally, we have an application.properties file where we have database details.

application.properties

# Connection url for the database
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.username=SYSTEM
spring.datasource.password=oracle3
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
# Show or not log for each sql query
spring.jpa.show-sql = true
 
 
spring.jpa.hibernate.ddl-auto =create
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.Oracle10gDialect
 
server.port = 9091

We are almost done. Just build the project once running the main method. Open git bash or cmd and Run mvn clean install.

Let’s deploy the application running SpringMain class as a java application.

JPA/Hibernate Eager vs Lazy loading Example using Spring Boot

Let’s see testing for JPA/Hibernate Eager vs Lazy Fetch Type Example using Spring Boot and Oracle.

Testing of example and query generated in both cases.

Sample request JSON data to perform save operation.

http://localhost:9091/book/savebook
{
	"bookName": "Premchand's best stories",
	"storyList": [{
			"storyName": "Stories of two oxes"
		},
		{
			"storyName": "idgah"
		}
	]
}

 

JPA/Hibernate Eager vs Lazy loading Example using Spring Boot

GET – http://localhost:9091/book/3

Query Generated in case of fetch = FetchType.LAZY while fetching Book entity.

Hibernate: 
    select
        book0_.book_id as book_id1_0_0_,
        book0_.book_name as book_name2_0_0_ 
    from
        book book0_ 
    where
        book0_.book_id=?
Hibernate: 
    select
        storylist0_.book_id as book_id3_1_0_,
        storylist0_.story_id as story_id1_1_0_,
        storylist0_.story_id as story_id1_1_1_,
        storylist0_.story_name as story_name2_1_1_ 
    from
        story storylist0_ 
    where
        storylist0_.book_id=?

Query Generated in case of fetch = FetchType.EAGER while fetching Book entity.

Hibernate: 
    select
        book0_.book_id as book_id1_0_0_,
        book0_.book_name as book_name2_0_0_,
        storylist1_.book_id as book_id3_1_1_,
        storylist1_.story_id as story_id1_1_1_,
        storylist1_.story_id as story_id1_1_2_,
        storylist1_.story_name as story_name2_1_2_ 
    from
        book book0_ 
    left outer join
        story storylist1_ 
            on book0_.book_id=storylist1_.book_id 
    where
        book0_.book_id=?

Observe both cases. In the case of fetch = FetchType.LAZY there are two separate queries getting prepared while in case of fetch = FetchType.EAGER only one query with Left Outer Join.

Note – There is an enum FetchType called in javax.persistence.

public enum FetchType {


    LAZY,

    EAGER
}

That’s all about JPA/Hibernate Lazy Vs Eager loading/Fetch Type Example using Spring Boot.

You may like.

Other Tutorial.

Fetch type docs.

Summary –  We have seen about Hibernate Eager vs Lazy loading Example. The fetch = FetchType.LAZY allows fetching child entity on demand. The fetch = FetchType.EAGER will load child entity along with the parent.