Spring Boot & JPA - Quick Guide



Spring Boot & JPA - Overview

Any enterprise application performs database operations by storing and retrieving vast amounts of data. Despite all the available technologies for storage management, application developers normally struggle to perform database operations efficiently.

Generally, Java developers use lots of code, or use the proprietary framework to interact with the database, whereas using JPA, the burden of interacting with the database reduces significantly. It forms a bridge between object models (Java program) and relational models (database program).

Mismatches between relational and object models

Relational objects are represented in a tabular format, while object models are represented in an interconnected graph of object format. While storing and retrieving an object model from a relational database, some mismatch occurs due to the following reasons−

  • Granularity − Object model has more granularity than relational model.

  • Subtypes − Subtypes (means inheritance) are not supported by all types of relational databases.

  • Identity − Like object model, relational model does not expose identity while writing equality.

  • Associations − Relational models cannot determine multiple relationships while looking into an object domain model.

  • Data navigation − Data navigation between objects in an object network is different in both models.

What is JPA?

Java Persistence API is a collection of classes and methods to persistently store the vast amounts of data into a database which is provided by the Oracle Corporation.

Where to use JPA?

To reduce the burden of writing codes for relational object management, a programmer follows the JPA Provider framework, which allows easy interaction with database instance. Here the required framework is taken over by JPA.

JPA

JPA History

Earlier versions of EJB, defined persistence layer combined with business logic layer using javax.ejb.EntityBean Interface.

  • While introducing EJB 3.0, the persistence layer was separated and specified as JPA 1.0 (Java Persistence API). The specifications of this API were released along with the specifications of JAVA EE5 on May 11, 2006 using JSR 220.

  • JPA 2.0 was released with the specifications of JAVA EE6 on December 10, 2009 as a part of Java Community Process JSR 317.

  • JPA 2.1 was released with the specification of JAVA EE7 on April 22, 2013 using JSR 338.

  • JPA 2.2 was released as a maintenance release in summer of 2017.

  • JPA 3.0 as part of Java EE project was transferred from Oracle to Eclipse Foundation and renamed as Jakarta EE. Packages were renamed from javax.persistence to jakarta.persistence.

  • Jakarta Persistance 3.1 was released in Sep'2022 as part of Jakarta EE 10

  • Jakarta Persistance 3.2 was released in Spring of 2024 as part of Jakarta EE 11

JPA Providers

JPA is an open source API, therefore various enterprise vendors such as Oracle, Redhat, Eclipse, etc. provide new products by adding the JPA persistence flavor in them. Some of these products include−

Hibernate, Eclipselink, Toplink, Spring Data JPA, etc.

Spring Boot & JPA - Environment Setup

This chapter will guide you on how to prepare a development environment to start your work with Spring Boot Framework and JPA. It will also teach you how to set up JDK and STS on your machine before you set up Spring Framework −

Step 1 - Setup Java Development Kit (JDK)

You can download the latest version of SDK from Oracle's Java site − Java SE Downloads. You will find instructions for installing JDK in downloaded files, follow the given instructions to install and configure the setup. Finally set PATH and JAVA_HOME environment variables to refer to the directory that contains java and javac, typically java_install_dir/bin and java_install_dir respectively.

If you are running Windows and have installed the JDK in C:\jdk-24, you would have to put the following line in your C:\autoexec.bat file.

set PATH=C:\jdk-24;%PATH% 
set JAVA_HOME=C:\jdk-24

Alternatively, on Windows NT/2000/XP, you will have to right-click on My Computer, select Properties → Advanced → Environment Variables. Then, you will have to update the PATH value and click the OK button.

On Unix (Solaris, Linux, etc.), if the SDK is installed in /usr/local/jdk-24 and you use the C shell, you will have to put the following into your .cshrc file.

setenv PATH /usr/local/jdk-24/bin:$PATH 
setenv JAVA_HOME /usr/local/jdk-24

Alternatively, if you use an Integrated Development Environment (IDE) like Borland JBuilder, Eclipse, IntelliJ IDEA, or Sun ONE Studio, you will have to compile and run a simple program to confirm that the IDE knows where you have installed Java. Otherwise, you will have to carry out a proper setup as given in the document of the IDE.

Step 2 - Setup Spring Tool Suite

All the examples in this tutorial have been written using Spring Tool Suite IDE. So we would suggest you should have the latest version of Spring Tool Suite installed on your machine.

To install Spring Tool Suite IDE, download the latest Spring Tool Suite binaries from www.eclipse.org/downloads. Once you download the installation, unpack the binary distribution into a convenient location. For example, in C:\sts\sts-4.30.0.RELEASE on Windows, or /usr/local/sts/sts-4.30.0.RELEASE on Linux/Unix and finally set PATH variable appropriately.

Spring Tool Suite can be started by executing the following commands on Windows machine, or you can simply double-click on SpringToolSuite4.exe

E:\sts\sts-4.30.0.RELEASE\SpringToolSuite4.exe 

Eclipse can be started by executing the following commands on Unix (Solaris, Linux, etc.) machine −

$/usr/local/sts/sts-4.30.0.RELEASE/SpringToolSuite4

Step 3 - Setup Spring Boot Project

Now if everything is fine, then you can proceed to set up your Spring Boot. Following are the simple steps to download and install the Spring Boot Project on your machine.

  • Go to spring Initializr link to create a spring boot project, https://start.spring.io/.

  • Select project as Maven Project.

  • Select language as Java.

  • Select Spring Boot version as 3.5.6.

  • Set Project Metadata - Group as com.tutorialspoint, Artifact as springboot-h2, name as springboot-h2, Description as Demo project for Spring Boot and package name as com.tutorialspoint.springboot-h2.

  • Select packaging as Jar.

  • Select java as 21.

  • Add dependencies as Spring Web, Spring Data JPA, H2 Database and Spring Boot DevTools.

Now click on GENERATE Button to generate the project structure.

Spring Initializr

Once the maven based spring boot project is downloaded, then import the maven project into eclipse and rest eclipse will handle. It will download the maven dependencies and build the project to make it ready for further development.

Step 4 - POSTMAN for REST APIs Testing

POSTMAN is a useful tool to test REST Based APIs. To install POSTMAN, download the latest POSTMAN binaries from www.postman.com/downloads/. Once you download the installable, follow the instructions to install and use it.

Spring Boot & JPA - Architecture

Java Persistence API or Jakarta Persistance API is a source to store business entities as relational entities. It shows how to define a PLAIN OLD JAVA OBJECT (POJO) as an entity and how to manage entities with relations.

Class Level Architecture

The following image shows the class level architecture of JPA. It shows the core classes and interfaces of JPA.

JPA Class Level Architecture

The following table describes each of the units shown in the above architecture.

Units Description
EntityManagerFactory This is a factory class of EntityManager. It creates and manages multiple EntityManager instances.
EntityManager It is an Interface, it manages the persistence operations on objects. It works like factory for Query instance.
Entity Entities are the persistence objects, stores as records in the database.
EntityTransaction It has one-to-one relationship with EntityManager. For each EntityManager, operations are maintained by EntityTransaction class.
Persistence This class contain static methods to obtain EntityManagerFactory instance.
Query This interface is implemented by each JPA vendor to obtain relational objects that meet the criteria.

The above classes and interfaces are used for storing entities into a database as a record. They help programmers by reducing their efforts to write codes for storing data into a database so that they can concentrate on more important activities such as writing codes for mapping the classes with database tables.

JPA Class Relationships

In the above architecture, the relations between the classes and interfaces belong to the jakarta.persistence package. The following diagram shows the relationship between them.

JPA Class Relationships
  • The relationship between EntityManagerFactory and EntityManager is one-to-many. It is a factory class to EntityManager instances.

  • The relationship between EntityManager and EntityTransaction is one-to-one. For each EntityManager operation, there is an EntityTransaction instance.

  • The relationship between EntityManager and Query is one-to-many. Many number of queries can execute using one EntityManager instance.

  • The relationship between EntityManager and Entity is one-to-many. One EntityManager instance can manage multiple Entities.

Spring Boot JPA vs Hibernate

JPA

JPA is a specification which specifies how to access, manage and persist information/data between java objects and relational databases. It provides a standard approach for ORM, Object Relational Mapping.

Hibernate

Hibernate is an implementation of JPA. It provides a lightweight framework and is one of the most popular ORM tool used.

JPA Vs Hibernate

Following table summerises the differences between JPA and Hibernate.

Category JPA Hibernate
Type JPA is a specification and defines the way to manage relational database data using java objects. Hibernate is an implementation of JPA. It is an ORM tool to persist java objects into the relational databases.
Package JPA uses javax.persistence package. Hibernate uses org.hibernate package.
Factory JPA uses EntityManagerFactory interface to get the entity manager to persist objects. Hibernate uses SessionFactory interface to create session object which is then used to persist objects.
CRUD Operations JPA uses EntityManager interface to create/read/delete operation and maintains the persistence context. Hibernate uses Session interface to create/read/delete operation and maintains the persistence context.
Language JPA uses JPQL (Java Persistence Query Language) as Object Oriented Query language for database operations. Hibernate uses HQL (Hibernate Query Language) as Object Oriented Query language for database operations.

Spring Boot & JPA - Application Setup

As in previous chapter Environment Setup, we've imported the generated spring boot project in eclipse. Now let's create the following structure in src/main/java folder.

Project Structure
  • com.tutorialspoint.controller.EmployeeController − A REST Based Controller to implement REST based APIs.

  • com.tutorialspoint.entity.Employee − An entity class representing the corresponding table in database.

  • com.tutorialspoint.repository.EmployeeRepository − A Repository Interface to implement the CRUD operations on the database.

  • com.tutorialspoint.service.EmployeeService − A Service Class to implement the business opearations over repository functions.

  • com.tutorialspoint.springbooth2.SprintBootH2Application − A Spring Boot Application class.

Example - JPA Based Spring Boot Application

SprintBootH2Application class is already present. We need to create the above packages and relevant classes and interface as shown below −

Entity - Entity.java

Following is the default code of Employee. It represents a Employee table with id, name, age and email columns.

package com.tutorialspoint.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table
public class Employee {

   // database column mappings
   @Id
   @Column
   private int id;

   @Column
   private String name;

   @Column
   private int age;

   @Column
   private String email;

   // setter/getter methods
   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 int getAge() {
      return age;
   }
   public void setAge(int age) {
      this.age = age;
   }

   public String getEmail() {
      return email;
   }
   public void setEmail(String email) {
      this.email = email;
   }
}

Repository - EmployeeRepository.java

Following is the default code of Repository to implement CRUD operations on above entity, Employee.

package com.tutorialspoint.repository;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.tutorialspoint.entity.Employee;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer>  {
}

Service - EmployeeService.java

Following is the default code of Service to implement operations over repository functions.

package com.tutorialspoint.service;

import java.util.ArrayList;
import java.util.List;

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

import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.repository.EmployeeRepository;

@Service
public class EmployeeService {
   
   @Autowired
   EmployeeRepository repository;
   
   // get an employee by id
   public Employee getEmployeeById(int id) {
      return repository.findById(id).get();
   }
   
   // get all employees
   public List<Employee> getAllEmployees(){
      List<Employee> employees = new ArrayList<Employee>();
      repository.findAll().forEach(employee -> employees.add(employee));
      return employees;
   }
   
   // create or update an employee
   public void saveOrUpdate(Employee employee) {
      repository.save(employee);
   }
   
   // delete an employee by id
   public void deleteEmployeeById(int id) {
      repository.deleteById(id);
   }
}

Controller - EmployeeController.java

Following is the default code of Controller to implement REST APIs.

package com.tutorialspoint.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.service.EmployeeService;

@RestController
@RequestMapping(path = "/emp")
public class EmployeeController {

   @Autowired
   EmployeeService employeeService;

   // get all employees
   @GetMapping("/employees")
   public List<Employee> getAllEmployees(){
      return employeeService.getAllEmployees();
   }

   // get an employee by id
   @GetMapping("/employee/{id}")
   public Employee getEmployee(@PathVariable("id") int id) {
      return employeeService.getEmployeeById(id);
   }

   // delete an employee by id
   @DeleteMapping("/employee/{id}")
   public void deleteEmployee(@PathVariable("id") int id) {
      employeeService.deleteEmployeeById(id);
   }

   // create an employee
   @PostMapping("/employee")
   public void addEmployee(@RequestBody Employee employee) {
      employeeService.saveOrUpdate(employee);   
   }

   // update an employee
   @PutMapping("/employee")
   public void updateEmployee(@RequestBody Employee employee) {
      employeeService.saveOrUpdate(employee);
   }	
}

Application - SprintBootH2Application.java

Following is the updated code of Application to use above classes.

package com.tutorialspoint.sprintbooth2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@ComponentScan({"com.tutorialspoint.controller","com.tutorialspoint.service"})
@EntityScan("com.tutorialspoint.entity")
@EnableJpaRepositories("com.tutorialspoint.repository")
@SpringBootApplication
public class SprintBootH2Application {
   public static void main(String[] args) {
      SpringApplication.run(SprintBootH2Application.class, args);
   }
}

Output

Create following maven configuration in eclipse to run the springboot application with goal spring-boot:run. This configuration will help to run the REST APIs and we can test them using POSTMAN.

Maven Configuration

Run the application

In eclipse, run the Employee Application configuration. Eclipse console will show the similar output.

[INFO] Scanning for projects...
[INFO] 
[INFO] [1m------------------< [0;36mcom.tutorialspoint:springboot-h2[0;1m >------------------[m
[INFO] [1mBuilding springboot-h2 0.0.1-SNAPSHOT[m
[INFO]   from pom.xml
[INFO] [1m--------------------------------[ jar ]---------------------------------[m
...

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.5.6)

2025-10-02T13:38:39.329+05:30  INFO 47300 --- [springboot-h2] [  restartedMain] c.t.s.SpringbootH2Application            : Starting SpringbootH2Application using Java 21.0.6 with PID 47300 (D:\Projects\springboot-h2\target\classes started by mahes in D:\Projects\springboot-h2)
...
2025-10-02T13:38:41.731+05:30  INFO 47300 --- [springboot-h2] [  restartedMain] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2025-10-02T13:38:41.949+05:30  WARN 47300 --- [springboot-h2] [  restartedMain] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2025-10-02T13:38:42.238+05:30  INFO 47300 --- [springboot-h2] [  restartedMain] o.s.b.a.h2.H2ConsoleAutoConfiguration    : H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem:testdb'
2025-10-02T13:38:42.313+05:30  INFO 47300 --- [springboot-h2] [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2025-10-02T13:38:42.353+05:30  INFO 47300 --- [springboot-h2] [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2025-10-02T13:38:42.361+05:30  INFO 47300 --- [springboot-h2] [  restartedMain] c.t.s.SpringbootH2Application            : Started SpringbootH2Application in 3.359 seconds (process running for 3.69)

Once server is up and running, Use Postman to make a POST request to add a record first.

Set the following parameters in POSTMAN.

  • HTTP Method - POST

  • URL - http://localhost:8080/emp/employee

  • BODY - An employee JSON

{  
   "id": "1",  
   "age": "35",  
   "name": "Julie",  
   "email": "julie@gmail.com"  
}   

Click on Send Button and check the response status to be OK.

Add Employee

Now make a GET Request to get all records.

Set the following parameters in POSTMAN.

  • HTTP Method - GET

  • URL - http://localhost:8080/emp/employees

Click the send button and verify the response.

Get All Employees

Spring Boot & JPA - Unit Test Repository

To test a Repository, we need the following annotation and classes −

  • @SpringBootTest(classes = SprintBootH2Application.class) − Configure the Spring Boot application.

  • @Transactional − To mark repository to do CRUD Operation capable.

  • @Autowired private EmployeeRepository employeeRepository − EmployeeRepository object to be tested.

Example - Unit testing a JPA Repository

Following is the complete code of EmployeeRepositoryTest.

EmployeeRepositoryTest.java

package com.tutorialspoint.repository;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.springboot_h2.SpringbootH2Application;

import jakarta.transaction.Transactional;

@Transactional
@SpringBootTest(classes = SpringbootH2Application.class)
public class  {

   @Autowired
   private EmployeeRepository employeeRepository;
   
   @Test
   public void testFindById() {
      Employee employee = getEmployee();	     
      employeeRepository.save(employee);
      Employee result = employeeRepository.findById(employee.getId()).get();
      assertEquals(employee.getId(), result.getId());	     
   }
   
   @Test
   public void testFindAll() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List<Employee> result = new ArrayList<>();
      employeeRepository.findAll().forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
   
   @Test
   public void testSave() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      Employee found = employeeRepository.findById(employee.getId()).get();
      assertEquals(employee.getId(), found.getId());	     
   }
   
   @Test
   public void testDeleteById() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      employeeRepository.deleteById(employee.getId());
      List<Employee> result = new ArrayList<>();
      employeeRepository.findAll().forEach(e -> result.add(e));
      assertEquals(result.size(), 0);
   }
   
   private Employee getEmployee() {
      Employee employee = new Employee();
      employee.setId(1);
      employee.setName("Mahesh");
      employee.setAge(30);
      employee.setEmail("mahesh@test.com");
      return employee;
   }
}

Run the test cases as JUnit Test

Output

Right Click on the file in eclipse and select Run a JUnit Test and verify the result.

Repository Test Result

Run the test cases using Maven Command.

Run the Test cases using Run As > Maven Test.

[INFO] Scanning for projects...
...
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.tutorialspoint.controller.[1mEmployeeControllerTest[m
21:31:59.404 [main] INFO org.springframework.boot.devtools.restart.RestartApplicationListener -- Restart disabled due to context in which it is running

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.5.6)

2025-10-01T21:31:59.827+05:30  INFO 36064 --- [springboot-h2] [           main] c.t.controller.EmployeeControllerTest    : Starting EmployeeControllerTest using Java 21.0.6 with PID 36064 (started by mahes in D:\Projects\springboot-h2)
2025-10-01T21:31:59.832+05:30  INFO 36064 --- [springboot-h2] [           main] c.t.controller.EmployeeControllerTest    : No active profile set, falling back to 1 default profile: "default"
2025-10-01T21:32:00.829+05:30  INFO 36064 --- [springboot-h2] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2025-10-01T21:32:00.869+05:30  INFO 36064 --- [springboot-h2] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 29 ms. Found 1 JPA repository interface.
Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK. Please add Mockito as an agent to your build as described in Mockito's documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html#0.3
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
2025-10-01T21:32:02.988+05:30  INFO 36064 --- [springboot-h2] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2025-10-01T21:32:03.441+05:30  INFO 36064 --- [springboot-h2] [           main] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:testdb user=SA
2025-10-01T21:32:03.451+05:30  INFO 36064 --- [springboot-h2] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2025-10-01T21:32:03.671+05:30  INFO 36064 --- [springboot-h2] [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2025-10-01T21:32:03.824+05:30  INFO 36064 --- [springboot-h2] [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 6.6.29.Final
2025-10-01T21:32:03.916+05:30  INFO 36064 --- [springboot-h2] [           main] o.h.c.internal.RegionFactoryInitiator    : HHH000026: Second-level cache disabled
2025-10-01T21:32:04.241+05:30  INFO 36064 --- [springboot-h2] [           main] o.s.o.j.p.SpringPersistenceUnitInfo      : No LoadTimeWeaver setup: ignoring JPA class transformer
...
2025-10-01T21:32:08.343+05:30  INFO 36064 --- [springboot-h2] [           main] c.t.repository.EmployeeRepositoryTest    : Started EmployeeRepositoryTest in 0.587 seconds (process running for 10.161)
...
[INFO] Results:
[INFO] 
[INFO] [1;32mTests run: 14, Failures: 0, Errors: 0, Skipped: 0[m
[INFO] 
[INFO] [1m------------------------------------------------------------------------[m
[INFO] [1;32mBUILD SUCCESS[m
[INFO] [1m------------------------------------------------------------------------[m
[INFO] Total time:  15.223 s
[INFO] Finished at: 2025-10-01T21:32:09+05:30
[INFO] [1m------------------------------------------------------------------------[m

Spring Boot & JPA - Repository Methods

Let's now analyze the methods available in repository interface which we've created.

Repository - EmployeeRepository.java

Following is the default code of Repository to implement CRUD operations on above entity, Employee.

package com.tutorialspoint.repository;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.tutorialspoint.entity.Employee;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer>  {
}

Now this repository contains following methods by default.

Sr.No Method & Description
1

count(): long

returns the number of entities available.

2

delete(Employee entity): void

deletes an entity.

3

deleteAll():void

deletes all the entities.

4

deleteAll(Iterable< extends Employee > entities):void

deletes the entities passed as argument.

5

deleteAll(Iterable< extends Integer > ids):void

deletes the entities identified using their ids passed as argument.

6

existsById(Integer id):boolean

checks if an entity exists using its id.

7

findAll():Iterable< Employee >

returns all the entities.

8

findAllByIds(Iterable< Integer > ids):Iterable< Employee >

returns all the entities identified using ids passed as argument.

9

findById(Integer id):Optional< Employee >

returns an entity identified using id.

10

save(Employee entity): Employee

saves an entity and return the updated one.

11

saveAll(Iterable< Employee> entities): Iterable< Employee>

saves all entities passed and return the updated entities.

Spring Boot & JPA - Custom Methods

We've checked the methods available by default in Repository in JPA Methods chapter. Now let's add a method and test it.

Example - Adding a custom method to repository

Add a method to find an employee by its name.

EmployeeRepository.java

package com.tutorialspoint.repository;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.tutorialspoint.entity.Employee;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer>  {
   public List<Employee> findByName(String name);	
   public List<Employee> findByAge(int age);
}

Now Spring JPA will create the implementation of above methods automatically as we've following the property based nomenclature. Let's test the methods added by adding their test cases in test file. Last two methods of below file tests the custom methods added.

Following is the complete code of EmployeeRepositoryTest.

EmployeeRepositoryTest.java

package com.tutorialspoint.repository;

import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.ArrayList;
import java.util.List;
import javax.transaction.Transactional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.sprintbooth2.SprintBootH2Application;

@Transactional
@SpringBootTest(classes = SprintBootH2Application.class)
public class EmployeeRepositoryTest {
   @Autowired
   private EmployeeRepository employeeRepository;
   @Test
   public void testFindById() {
      Employee employee = getEmployee();	     
      employeeRepository.save(employee);
      Employee result = employeeRepository.findById(employee.getId()).get();
      assertEquals(employee.getId(), result.getId());	     
   }
   @Test
   public void testFindAll() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List<Employee> result = new ArrayList<>();
      employeeRepository.findAll().forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
   @Test
   public void testSave() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      Employee found = employeeRepository.findById(employee.getId()).get();
      assertEquals(employee.getId(), found.getId());	     
   }
   @Test
   public void testDeleteById() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      employeeRepository.deleteById(employee.getId());
      List<Employee> result = new ArrayList<>();
      employeeRepository.findAll().forEach(e -> result.add(e));
      assertEquals(result.size(), 0);
   }
   private Employee getEmployee() {
      Employee employee = new Employee();
      employee.setId(1);
      employee.setName("Mahesh");
      employee.setAge(30);
      employee.setEmail("mahesh@test.com");
      return employee;
   }
   @Test
   public void testFindByName() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List<Employee> result = new ArrayList<>();
      employeeRepository.findByName(employee.getName()).forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
   @Test
   public void testFindByAge() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List<Employee> result = new ArrayList<>();
      employeeRepository.findByAge(employee.getAge()).forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
}

Run the test cases

Output

Right Click on the file in eclipse and select Run a JUnit Test and verify the result.

Repository Test Custom Methods

Spring Boot & JPA - Named Queries

Some time case arises, where we need a custom query to fulfil one test case. We can use @NamedQuery annotation to specify a named query within an entity class and then declare that method in repository. Following is an example.

We've added custom methods in Repository in JPA Custom Methods chapter. Now let's add another method using @NamedQuery and test it.

Example - Usage of Named Query in JPA

Entity - Employee.java

Following is the default code of Employee. It represents a Employee table with id, name, age and email columns.

package com.tutorialspoint.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.Table;

@Entity
@Table
@NamedQuery(name = "Employee.findByEmail",
query = "select e from Employee e where e.email = ?1")
public class Employee {
   @Id
   @Column
   private int id;

   @Column
   private String name;

   @Column
   private int age;

   @Column
   private String email;

   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 int getAge() {
      return age;
   }
   public void setAge(int age) {
      this.age = age;
   }
   public String getEmail() {
      return email;
   }
   public void setEmail(String email) {
      this.email = email;
   }
}

Repository - EmployeeRepository.java

Add a method to find an employee by its name and age.

package com.tutorialspoint.repository;

import java.util.List;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.tutorialspoint.entity.Employee;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer>  {
   public List<Employee> findByName(String name);	
   public List<Employee> findByAge(int age);
   public Employee findByEmail(String email);
}

Now Spring JPA will create the implementation of above methods automatically using the query provided in named query. Let's test the methods added by adding their test cases in test file. Last method of below file tests the named query method added.

Following is the complete code of EmployeeRepositoryTest.

package com.tutorialspoint.repository;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.springboot_h2.SpringbootH2Application;

import jakarta.transaction.Transactional;

@Transactional
@SpringBootTest(classes = SpringbootH2Application.class)
public class EmployeeRepositoryTest {
   @Autowired
   private EmployeeRepository employeeRepository;

   @Test
   public void testFindById() {
      Employee employee = getEmployee();	     
      employeeRepository.save(employee);
      Employee result = employeeRepository.findById(employee.getId()).get();
      assertEquals(employee.getId(), result.getId());	     
   }
   @Test
   public void testFindAll() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List<Employee> result = new ArrayList<>();
      employeeRepository.findAll().forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
   @Test
   public void testSave() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      Employee found = employeeRepository.findById(employee.getId()).get();
      assertEquals(employee.getId(), found.getId());	     
   }
   @Test
   public void testDeleteById() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      employeeRepository.deleteById(employee.getId());
      List<Employee> result = new ArrayList<>();
      employeeRepository.findAll().forEach(e -> result.add(e));
      assertEquals(result.size(), 0);
   }
   private Employee getEmployee() {
      Employee employee = new Employee();
      employee.setId(1);
      employee.setName("Mahesh");
      employee.setAge(30);
      employee.setEmail("mahesh@test.com");
      return employee;
   }
   @Test
   public void testFindByName() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List<Employee> result = new ArrayList<>();
      employeeRepository.findByName(employee.getName()).forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
   @Test
   public void testFindByAge() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List<Employee> result = new ArrayList<>();
      employeeRepository.findByAge(employee.getAge()).forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
   @Test
   public void testFindByEmail() {	     
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      Employee result = employeeRepository.findByEmail(employee.getEmail());	     
      assertNotNull(result);	     
   }
}

Run the test cases

Right Click on the file in eclipse and select Run a JUnit Test and verify the result.

Repository Test Named Query method

Spring Boot & JPA - Custom Query

Some time case arises, where we need a custom query to fulfil one test case. We can use @Query annotation to specify a query within a repository. Following is an example. In this example, we are using JPQL, Java Persistence Query Language.

We've added name query custom methods in Repository in JPA Named Query chapter. Now let's add another method using @Query and test it.

Example - Usage of Custom Query in JPA

Repository - EmployeeRepository.java

Add a method to get list of employees order by their names.

package com.tutorialspoint.repository;

import java.util.List;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.tutorialspoint.entity.Employee;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer>  {
   public List<Employee> findByName(String name);	
   public List<Employee> findByAge(int age);
   public Employee findByEmail(String email);
   
   @Query(value = "SELECT e FROM Employee e ORDER BY name")
   public List<Employee> findAllSortedByName();
}

EmployeeRepositoryTest.java

Let's test the methods added by adding their test cases in test file. Last method of below file tests the custom query method added.

Following is the complete code of EmployeeRepositoryTest.

package com.tutorialspoint.repository;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.springboot_h2.SpringbootH2Application;

import jakarta.transaction.Transactional;

@Transactional
@SpringBootTest(classes = SpringbootH2Application.class)
public class EmployeeRepositoryTest {
   @Autowired
   private EmployeeRepository employeeRepository;
   @Test
   public void testFindById() {
      Employee employee = getEmployee();	     
      employeeRepository.save(employee);
      Employee result = employeeRepository.findById(employee.getId()).get();
      assertEquals(employee.getId(), result.getId());	     
   }
   @Test
   public void testFindAll() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List>Employee> result = new ArrayList>>();
      employeeRepository.findAll().forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
   @Test
   public void testSave() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      Employee found = employeeRepository.findById(employee.getId()).get();
      assertEquals(employee.getId(), found.getId());	     
   }
   @Test
   public void testDeleteById() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      employeeRepository.deleteById(employee.getId());
      List>Employee> result = new ArrayList>>();
      employeeRepository.findAll().forEach(e -> result.add(e));
      assertEquals(result.size(), 0);
   }
   private Employee getEmployee() {
      Employee employee = new Employee();
      employee.setId(1);
      employee.setName("Mahesh");
      employee.setAge(30);
      employee.setEmail("mahesh@test.com");
      return employee;
   }
   @Test
   public void testFindByName() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List>Employee> result = new ArrayList>>();
      employeeRepository.findByName(employee.getName()).forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
   @Test
   public void testFindByAge() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List>Employee> result = new ArrayList>>();
      employeeRepository.findByAge(employee.getAge()).forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
   @Test
   public void testFindByEmail() {	     
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      Employee result = employeeRepository.findByEmail(employee.getEmail());	     
      assertNotNull(result);	     
   }
   @Test
   public void testFindAllSortedByName() {
      Employee employee = getEmployee();
      Employee employee1 = new Employee();
      employee1.setId(2);
      employee1.setName("Aarav");
      employee1.setAge(20);
      employee1.setEmail("aarav@test.com");
      employeeRepository.save(employee);	     
      employeeRepository.save(employee1);
      List>Employee> result = employeeRepository.findAllSortedByName();
      assertEquals(employee1.getName(), result.get(0).getName());	     
   }
}

Run the test cases

Right Click on the file in eclipse and select Run a JUnit Test and verify the result.

Repository Test Custom Query method

Spring Boot & JPA - Native Query

Some time case arises, where we need a custom native query to fulfil one test case. We can use @Query annotation to specify a query within a repository. Following is an example. In this example, we are using native query, and set an attribute nativeQuery=true in Query annotation to mark the query as native.

We've added custom methods in Repository in JPA Custom Query chapter. Now let's add another method using native query and test it.

Example - Usage of Native Query in JPA

Repository - EmployeeRepository.java

Add a method to get list of employees order by their names.

package com.tutorialspoint.repository;

import java.util.List;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.tutorialspoint.entity.Employee;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer>  {
   public List<Employee> findByName(String name);	
   public List<Employee> findByAge(int age);
   public Employee findByEmail(String email);
   
   @Query(value = "SELECT e FROM Employee e ORDER BY name")
   public List<Employee> findAllSortedByName();

   @Query(value = "SELECT * FROM Employee ORDER BY name", nativeQuery = true)
   public List<Employee> findAllSortedByNameUsingNative();
}

EmployeeRepositoryTest.java

Let's test the methods added by adding their test cases in test file. Last method of below file tests the native query method added.

Following is the complete code of EmployeeRepositoryTest.

package com.tutorialspoint.repository;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.springboot_h2.SpringbootH2Application;

import jakarta.transaction.Transactional;

@Transactional
@SpringBootTest(classes = SpringbootH2Application.class)
public class EmployeeRepositoryTest {
   @Autowired
   private EmployeeRepository employeeRepository;
   @Test
   public void testFindById() {
      Employee employee = getEmployee();	     
      employeeRepository.save(employee);
      Employee result = employeeRepository.findById(employee.getId()).get();
      assertEquals(employee.getId(), result.getId());	     
   }
   @Test
   public void testFindAll() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List>Employee> result = new ArrayList>>();
      employeeRepository.findAll().forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
   @Test
   public void testSave() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      Employee found = employeeRepository.findById(employee.getId()).get();
      assertEquals(employee.getId(), found.getId());	     
   }
   @Test
   public void testDeleteById() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      employeeRepository.deleteById(employee.getId());
      List>Employee> result = new ArrayList>>();
      employeeRepository.findAll().forEach(e -> result.add(e));
      assertEquals(result.size(), 0);
   }
   private Employee getEmployee() {
      Employee employee = new Employee();
      employee.setId(1);
      employee.setName("Mahesh");
      employee.setAge(30);
      employee.setEmail("mahesh@test.com");
      return employee;
   }
   @Test
   public void testFindByName() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List>Employee> result = new ArrayList>>();
      employeeRepository.findByName(employee.getName()).forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
   @Test
   public void testFindByAge() {
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      List>Employee> result = new ArrayList>>();
      employeeRepository.findByAge(employee.getAge()).forEach(e -> result.add(e));
      assertEquals(result.size(), 1);	     
   }
   @Test
   public void testFindByEmail() {	     
      Employee employee = getEmployee();
      employeeRepository.save(employee);
      Employee result = employeeRepository.findByEmail(employee.getEmail());	     
      assertNotNull(result);	     
   }
   @Test
   public void testFindAllSortedByName() {
      Employee employee = getEmployee();
      Employee employee1 = new Employee();
      employee1.setId(2);
      employee1.setName("Aarav");
      employee1.setAge(20);
      employee1.setEmail("aarav@test.com");
      employeeRepository.save(employee);	     
      employeeRepository.save(employee1);
      List>Employee> result = employeeRepository.findAllSortedByName();
      assertEquals(employee1.getName(), result.get(0).getName());	     
   }
   @Test
   public void testFindAllSortedByNameUsingNative() {
      Employee employee = getEmployee();
      Employee employee1 = new Employee();
      employee1.setId(2);
      employee1.setName("Aarav");
      employee1.setAge(20);
      employee1.setEmail("aarav@test.com");
      employeeRepository.save(employee);	     
      employeeRepository.save(employee1);
      List<Employee> result = employeeRepository.findAllSortedByNameUsingNative();
      assertEquals(employee1.getName(), result.get(0).getName());	     
   }
}

Run the test cases

Right Click on the file in eclipse and select Run a JUnit Test and verify the result.

Repository Test Native Query Method
Advertisements