Enterprise Java

Spring Data JPA Tutorial

Managing data between java classes or objects and the relational database is a very cumbersome and tricky task. The DAO layer usually contains a lot of boilerplate code that should be simplified in order to reduce the number of lines of code and make the code reusable.

In this tutorial, we will discuss spring data’s implementation of JPA.

1. Introduction

1.1 What is JPA?

JPA or Java Persistence API is the Java specification for accessing, managing and persisting data between Java classes or objects and relational database. The specification was introduced as part of EJB 3.0.

JPA is not an implementation or product, it is just a specification. It contains set of interfaces which need to be implemented. It is a framework that provides an extra layer of abstraction on the JPA implementation. The repository layer will contain three layers as mentioned below.

  • Spring Data JPA: – This provides spring data repository interfaces which are implemented to create JPA repositories.
  • Spring Data Commons: – It provides the infrastructure that is shared between data store specific spring data projects.
  • The JPA provider which implements the JPA persistence API.

Spring data JPA allows us not to write any boilerplate code by adding an additional repository layer.

1.2 History of JPA

JPA2.0: – The development of JPA2.0 started in 2007 as JSR 317. The version was marked as 2.0 as it could not gain the common consensus for 1.0. The focus was to address the features available as part of famous vendor ORMs.

JPA 2.1:- JPA2.1 started in July 2011 as JSR 338. Some of the main features were Entity graph, stored procedures, converters, etc.

JPA 2.2:- JPA2.2 is the latest addition to JPA series in 2017. It includes support for Java 8 date and time type, ability to stream a query result.

JPA is still undergoing lot of changes and we can epect a newer version of JPA soon.

1.3 Spring Data Repositories

Spring Data Commons project provides repository abstraction which is extended by the datastore-specific subprojects.

We have to be familiar with the Spring Data repository interfaces as it will help us with the implementation of the interfaces. Let’s have a look at the interfaces.

Spring Data Commons: – Following interfaces are provided as part of this project:

Spring Data JPA: –  This project provides the following interfaces:

  • JpaRepository<T, ID extends Serializable>  : This interface is a JPA specific repository interface that combines the methods declared by the common repository interfaces behind a single interface.
  • JpaSpecificationExecutor<T> : This is again not a “repository interface”. It declares the methods that are used to retrieve entities from the database by using Specification<T> objects that use the JPA criteria API.

The repository hierarchy looks as follows:

Spring Data Repository Hierarchy

Let’s try to understand Spring Data JPA through a sample program.

1.4 Spring Data Custom Query

Let us consider a use case where we have to fetch data from a database based on a query. Writing a custom query is a very useful case. Spring Data JPA has different ways of writing custom queries. We will broadly classify the ways as mentioned below.

Automatic Custom Queries: The automatic custom query creation is also known as query creation from the method name. Spring Data JPA has a built-in mechanism for query creation which can be used for parsing queries straight from the method name of a query method. The mechanism first removes common prefixes from the method name and parses the constraints of the query from the rest of the method name. In order to use this approach, we have to make sure the method names of your repository interface are created by combining the property names of an entity object and the supported keywords.

The advantage of using this approach is that it makes it very easy to implement. But the limitation is if the query contains more than one parameter than the method name will be not readable. Also the keywords that are not supported by JPA like lower will not be useful with this approach.

Manual Custom Queries: Manual Custom queries are also known as queries creation using @Query tag. The @Query annotation will be used to create queries using the JPA query language and for binding these queries directly to the methods of your repository interface. When the query method is called, Spring Data JPA will execute the query specified by the @Query annotation.

The advantage of this approach is you can use JPA query language for the creation of a query. Also, the query stays in repository layer. Limitation of this approach is @Query can be only used when JPA query language is supported.

The program mentioned below uses both the approaches.

1.5 Spring Data JPA Exception Translation

The point to consider is because the default Spring ORM templates are not used with SPring JPA, are we losing exception translation by using Spring Data JPA?nAre we not going to get our JPA exceptions translated to Spring’s DataAccessException hierarchy?

The answer is No. Exception translation is still enabled by the use of the annotation@Repository on the DAO. The annotation enables a Spring bean postprocessor to advice all @Repository beans with all the PersistenceExceptionTranslator instances found in the Container and provides exception translation just as before.

2. Tools and Technologies

Let us look at the technologies and tool used for building the program.

  • Eclipse Oxygen.2 Release (4.7.2)
  • Java – version 9.0.4
  • Maven – 3.5.3
  • Spring boot – 2.0.1-Release
  • Postgresql – 10
  • postman

3. Project Structure

Our project structure will look as shown in the image below.

Project Structure for Spring Data JPA Tutorial

 

The above project structure is using Maven. This project can also be created using Gradle and the pom.xml will get replaced with build.gradle file. The structure of the project will defer slightly with the usage of Gradle for the build.

4. An objective of the Program

As part of the program, we will try to create a simple web service using spring boot. This web service will be used for data manipulation on PostgreSQL database.

4.1 pom.xml

The pom.xml file for the program will look as mentioned below.

pom.xml for SpringData JPA with Spring Boot

<?xml version="1.0" encoding="UTF-8"?>
<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>com.springjpa</groupId>
	<artifactId>SpringJPA-PostgreSQL</artifactId>
	<version>0.0.1</version>
	<packaging>jar</packaging>

	<name>SpringJPA-PostgreSQL</name>
	<description>Demo project for Spring Boot JPA - PostgreSQL</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.1.RELEASE</version>
		<relativePath/> 
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.9</java.version>
	</properties>

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

		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
  <groupId>javax.xml.bind</groupId>
  <artifactId>jaxb-api</artifactId>
  <version>2.3.0</version>
</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
	


</project>

The pom.xml file will contain the dependencies that will be needed as part of the program.

4.2 Application class

The Application.java class for us is SpringJpaPostgreSqlApplication.java class. The class looks as shown below.

SpringJpaPostgreSqlApplication.java class for Spring Boot

package com.tutorial;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.tutorial.repo.EmployeeRepository;

@SpringBootApplication
public class SpringJpaPostgreSqlApplication implements CommandLineRunner{

	@Autowired
	EmployeeRepository repository;
	
	public static void main(String[] args){
		SpringApplication.run(SpringJpaPostgreSqlApplication.class, args);
	}

	public void run(String... args) throws Exception {
		// TODO Auto-generated method stub
		
	}

}

The CommandLineRunner interface is used for to indicate that a bean should run when it is contained within a Spring Application.

4.3 Model Class

We are going to create an Employee.java class as the model class. The class will look as shown below.

Model class for the program

package com.tutorial.model;

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.Table;

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

	private static final long serialVersionUID = -3009157732242241606L;
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name="id")
	private long id;

	@Column(name = "firstname")
	private String firstName;

	@Column(name = "lastname")
	private String lastName;
	
	@Column(name = "age")
	private int age;

	protected Employee() {
	}

	public Employee(String firstName, String lastName,int age) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.age = age;
	}

	@Override
	public String toString() {
		return String.format("Employee[id=%d, firstName='%s', lastName='%s', age='%d']", id, firstName, lastName,age);
	}

	
	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLast_Name(String lastName) {
		this.lastName = lastName;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

@Entity: Is used to define that the class is an Entity class.
@Table: This annotation is used for specifying the table name which is defined in the database.
@Id: Id annotation is used for specifying the Id attribute
@GeneratedValue: This is used when we want to set automatically generated value. GenerationType is the mechanism that is used for generating the value for the specific column.
@Column: This annotation is used for mapping the columns from the table with the attributes in the class.


 

4.4 Repository Interface

The repository interface is used for extending the CRUD interface. This interface adds the layer of a repository in the program. Spring Data JPA provides two major ways of creating queries. These queries are then used in the repository interface to fetch the data from the database.

Repository class for extending CRUD repository

package com.tutorial.repo;

import java.util.List;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import com.tutorial.model.Employee;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Long>{
	List findByLastName(String lastName);
	
@Query("SELECT e FROM Employee e WHERE e.age = :age")
    public List findByAge(@Param("age") int age);
}

The CrudRepository is the interface from SpringData Common project. The two methods mentioned above for query creation is used at the below-mentioned places in the code.

Automatic Custom Query:

 List findByLastName(String lastName);

The method findByLastName contains the last name as the parameter which will be used for the search of data. Also, the query will be automatically created using JPA query builder.

Manual Custom Query:

 @Query("SELECT e FROM Employee e WHERE e.age = :age")
    public List findByAge(@Param("age") int age);

In this method we have manually defined a query to fetch the data based on age and the query is then bound with the findByAge method.

4.5 Properties file

As part of spring boot for connecting to the database, we will provide the details in the properties file. The properties file will look as shown below.

application.properties file for the spring boot

spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=password
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

As part of the properties file, the database URL and credentials are provided. The property spring.jpa.show-sql=true shows the SQL query generated during the data manipulation by JPA.

4.6 Controller class

The controller is the most important class of the complete program. This is the class responsible for all the url mapping. We have added the repository methods for data manipulation in this class itself.

Controller class for the program

package com.tutorial.controller;

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.tutorial.model.Employee;
import com.tutorial.repo.EmployeeRepository;

@RestController
@RequestMapping("/employee")
public class WebController {
	@Autowired
	EmployeeRepository repository;
	
	@RequestMapping(value="/save",method = RequestMethod.POST)
	public HttpStatus insertEmployee(@RequestBody Employee employee){
		boolean status = repository.save(employee) != null;		
		return status? HttpStatus.CREATED : HttpStatus.BAD_REQUEST;
	}
	
	
	@RequestMapping("/findall")
	public List findAll(){
		
		
		return (List) repository.findAll();
	}
	
	@RequestMapping("/findbyid")
	public Optional findById(@RequestParam("id") long id){
		Optional result = repository.findById(id);
		return result;
	}
	
	@RequestMapping("/findbylastname")
	public List fetchDataByLastName(@RequestParam("lastname") String lastName){
		 		
		return repository.findByLastName(lastName);
	}
	@RequestMapping("/findbyage")
	public List fetchDataByAge(@RequestParam("age") int age){
		 		
		return repository.findByAge(age);
	}
}

@RestController tag is used for defining the class as a rest controller class.
@RequestMapping tag specifies the path mapping for the request. Value attribute specifies the URL mapping and the method attributes specifies the type of method it is like GET, POST, PUT, etc.
If we don’t specify the method attribute by default the method is considered as GET method.

In this class, we have autowired the repository and are using the methods available in the interface for data retrieval, insertion and deletion.

For running the spring boot application we have to provide the command spring-boot: run .

5. Output

Below mentioned queries can be used for the creation of Employee table in PostgreSQL.

SQL query for Employee table creation

create table employee (
id serial not null primary key,
firstName varchar(20) not null,
lastName varchar(20) not null,
age integer not null
);

Lets us check the data available in the database. The current data available in the database is shown below.

Data in PostgreSQL

Now let’s try the findall API using postman collection to get the rows as result. The result will look as shown below on postman.

Result of findall API on postman

In order to add some employee object in a database. We will use the save API and will pass an employee object.

Object storage in DB with save API

Let’s check the database post the save API usage. The database will look as shown below.

After the data is saved using Save API

Similarly, we can use the findbylastname API for finding the records having the last name provided in the request parameter.

Result of findbylastname API

Let’s see the result for the method which is bound to manual custom query.

Result of findByAge API

6. Summary

The summary of the tutorial is mentioned below.

  1. SpringData JPA provides repository abstraction which is used for JPA persistence APIs.
  2. We learned about the usage of CRUD repository.
  3. We used automatic custom queries for searching the rows based on the last name.
  4. We learned about manual custom query creation.
  5. The JPA exception translation is dependent on @Repository tag.

7. Download the Eclipse project

This was a tutorial for SpringData JPA with SpringBoot.

You can download the full source code of this example here: SpringJPA-PostgreSQL.zip

Anand Kumar

Anand has graduated from Kuvempu University, India in Electronics and Instrumentation department. He has over 8 years of IT experience and is mainly involved in design and programming for websites and server side logic using Java oriented technologies like spring-boot, spring-data, spring-security, Hibernate, etc. He has worked with start-up companies and small business setup to Large Multinational companies.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Ravindra
Ravindra
4 years ago

How it is getting connected to database?
How the spring boot is accessing the application.properties?
can use give a detailed explanation?

Rama Koteswararao Gutta
Rama Koteswararao Gutta
3 years ago

Thank you very much for the detailed explanation in theoritically and practically. you saved my R&D time of the Spring Data JPA subject.

Back to top button