Spring Data – JPA

Spring Data Initial Concept

A brief discussion on the Initial Concept of Spring Data is described in this springcavaj – Spring Data page with an architecture diagram.

This guide will provide you the understanding of using Spring Data to build an application that stores and retrieves data using MySQL as the underlying database.

Advantage of using Spring Data with MySQL

  • No-code Repositories – One of the most popular persistence-related patterns is the Repository Pattern. It helps the developer to only focus on the implementation of business logic and hides the data store specific implementation details.
    import org.springframework.data.mongodb.repository.JpaRepository;
    import org.springframework.stereotype.Repository;
    @Repository
    public interface SpringDataRestRepositoryextendsJpaRepository<User, Long>

Here, you can see that I have used JpaRepository to perform the CRUD operations on the entity – User. Because in this example, I have used MySQL as the underlying database. JpaRepository extends PagingAndSortingRepository and QueryByExampleExceutor interfaces. By this implementation you will get the default implementations of methods like:

  1. To insert, update and delete one or more User
  2. To find one or more User by their primary keys
  3. To count, get and delete all Users
  4. To check if a User with a given primary key already exists or not
  • Reduce boilerplate code – Spring-Data provides a default implementation for each method like read or write operations.
  • Generated Queries – Spring-Data generates the database queries based on their method names. You just need to define a method in your repository interface with a name that starts with findBy.
    @Repository
    public interface SpringDataRestRepository extends JpaRepository<User, Long> {
         public List<User> findByFirstName(String firstName);
         public List<User> findByLastName(String lastName);
         public List<User> findByMobileNo(String mobileNo);
         public List<User> findByEmail(String email);
         public User findByPanNo(String panNo);
    }

Here you can see that this Repository Interface extends JpaRepository and I have attached the User entity in the concept of Generics as the 1st argument and in the 2nd argument provide the data type of the Primary Key as defined in the entity. In my case the data type of the primary key used in User entity is Long.

Using Spring Data with Spring Boot and use MySQL DB as database

The introduction of Spring-Data makes the implementation of the persistent layers much easier for a developer. For this, let’s make our hands dirty by creating a project. I have created a Demo project named spring-data-jpa-masterclass and uploaded it to my personal GitHub account. One can clone the project and can test it locally in their system. All the steps that are required to download the project from GitHub and run it locally are mentioned in the README.md file of spring-data-jpa-masterclass repository.

  • Brief Description – In this project spring-data-jpa-masterclass, I have used Spring Boot, Maven, Java, and MySQL as the underlying database. In this project, I mainly focus on implementing the Spring-data with Spring-REST service. It consists of a Controller annotated with @RestController annotation, a Repository extending the JpaRepository, and the CRUD operations to the MySQL Database. To test the Services, I have used Postman.
  • Software Used – Software required to develop this project.
    • Spring Tool Suite-4.7.0-RELEASE – If the latest version is available then download that one
    • Apache Maven 3.6.3 – If the latest version is available then download that one
    • Java 8 – Not less than Java8
    • Git 2.27.0 – Latest version as available
    • MySQL Workbench 8.0 CE – MySQL DB Server – Community Edition
    • SQLYog – One can use SQLYog in replacement of MySQL Workbench
    • Postman v8.3.0 – To test the REST Service
    • A list of the software and their download link with the installation steps are briefly described in the README.md file of spring-data-jpa-masterclass repository
  • Project Components – The project that I develop in support of the spring-data with the JPA concept is a Maven project. And I have used two dependencies as spring-boot-starter-data-jpa and mysql-connector-java. The reason behind this as I have used MySQL DB as the underlying database.
    <!--  Spring Data Dependency -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!--  MySQL Connector Dependency -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

In the next step, I have configured the database connection in application.properties file. You can use either application.properties or application.yml file. A wonderful concept using Spring Boot and Spring Data is that they handle the default configuration for you, you only need to override the parameters you want to change.

spring.application.name=spring-data-jpa-crud
server.port=7110
## Database Properties
spring.datasource.url=jdbc:mysql://localhost:3306/spring
spring.datasource.username=root
spring.datasource.password=Provide the password for your choice when you install MySQL DB in your machine.
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto=update

I would like to discuss a little bit on 2 properties as defined above:

  1. spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect ⇾ This property is used to connect to MySQL DB from the application I have developed. Dialect means the language through which hibernate will talk with the underlying database, here the database is MySQL Database.
  2. spring.jpa.hibernate.ddl-auto=update ⇾ This property is to tell hibernate how I want my database should be created and updated. The value is updated, which means that if the database is not there then it will create for the first time, and from the second time, hibernate will update that database.
  • Structure of the Project – To use Spring Data and its libraries in your project, you need to structure it in the right way.

Spring Boot expects that all source files are located in sub-packages of the class annotated with @SpringBootApplication. In the above sample project, I have one class named SpringDataJpaRestApplication.java which has the @SpringBootApplication annotations in it. And it is the starting point of the application.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringDataJpaRestApplication {
        public static void main(String[] args) {
            SpringApplication.run(SpringDataJpaRestApplication.class, args);
	}
}

As I have used MySQL as the underlying database, so I have provided 4 SQL Scripts to create the schema and database in MySQL. If any problem happens while creating the schema and database in MySQL, I have also provided 2 SQL Scripts that will delete the database and schema. I have provided a brief description of the necessary execution steps of those scripts in the README.md file of the project. Please have a look there.

Scripts are available in the src/main/sql_scripts folder.

  • Spring-Data Implementation – To implement Spring-Data I have used one of its dependencies named spring-boot-starter-data-jpa. For this, you need to define one model class that will interact with the database and a Repository interface that you will use for the CRUD operations with the database.

Let’s look at the Model class, first named User.java

    @Entity
    @Table(name="user")
    @EntityListeners(AuditingEntityListener.class)
    public class User implements Serializable {
	private static final long serialVersionUID = -4438854508205345577L;	
	@Id
        @GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "user_id", nullable = false)
	private Long userId;
        @Column(name = "first_name", nullable = false)
	private String firstName;
        @Column(name = "middle_name")
	private String middleName;
        @Column(name = "last_name", nullable = false)
	private String lastName;
        @Column(name = "mobile_no", nullable = false)
	private String mobileNo;
        @Column(name = "email", nullable = false)
	private String email;
        @Column(name = "pan_no", nullable = false)
	private String panNo;

Here you can see that the Model class name is User annotated with @Entity and @Table(name=”user”) annotations. @Entity annotation will let hibernate know that this model class will be persisted in DB. And @Table annotation is used to persist the User model data in the User table. And for this, the primary key is userId as the property is annotated with @Id annotation. And it has a @GeneratedValue(strategy = GenerationType.AUTO), it means that I provide a strategy to save the value of the Primary Key. It will be a number generated automatically and increment by 1 for each record that get inserted in MySQL DB.

Now we will explore the Repository interface

    @Repository
    public interface SpringDataRestRepository extends JpaRepository<User, Long>{
	public List<User> findByFirstName(String firstName);
	public List<User> findByLastName(String lastName);
	public List<User> findByMobileNo(String mobileNo);
	public List<User> findByEmail(String email);
	public User findByPanNo(String panNo);
	@Query("FROM User where firstName = ?1 and lastName = ?2")
	public User findByFirstAndLastName(String firstName, String lastName);
  }

Here you can see that the methods are declared by following a naming convention as findBy then the name of the property as defined in the User model. And the best thing is that you don’t need to provide any implementation for this. As, spring-data itself provides that.

Here I have used one custom query example to find the record based on firstName and lastName. I have used one annotation as @Query(“FROM User where firstName = ?1 and lastName = ?2”). A brief description of the query used in @Query annotation. It is called as JPL Query. In this query I have written as FROM User, here User is the name of the model defined and the clause where firstName = ?1 and lastName = ?2, here firstName and lastName are the properties defined in that User class. In this project, I have also used @RestController and use the Spring-Rest annotations as @GetMapping, @PostMapping, @PutMapping and @DeleteMapping.This project has no UI implementation. If anyone try to integrate UI then one can clone the repository and add the UI components there.

  • Testing the application – In this application there is no UI component. So, I have used Postman to test the REST endpoint as defined.
    1. You clone the application from GitHub and set up the application locally in any one of the IDEs like Spring Tool Suite (STS) or Eclipse.
    2. Right-click on the application
    3. Click the Option Run As
    4. Select the option Spring Boot App.
    5. It will start the application in port no 7110.
    6. Now, in Postman, you can test the endpoints.

Below, I have provided the list of endpoints as available in this application.

  1. Get all Userslocalhost:7110/allUsers
  2. Save an Userlocalhost:7110/saveUser, in the Body provide the JSON Object. A dummy JSON object is provided.
  3. Update an Userlocalhost:7110/updateUser/{id}, in the Body again provides the JSON data.
  4. Delete an Userlocalhost:7110/deleteUser/{id}
  5. Get User By First Name localhost:7110/getUserByFirstName/{firstName}
  6. Get User By Last Namelocalhost:7110/getUserByLastName/{lastName}
  7. Get User By Mobile Nolocalhost:7110/getUserByMobileNo/{mobileNo}
  8. Get User By Emaillocalhost:7110/getUserByEmail/{email}
  9. Get User By Pan Nolocalhost:7110/getUserByPan/{panNo}
  10. Get User By Namelocalhost:7110/getUserByName/{firstName}/{lastName}
  • Sample JSON Data – I have provided 2 sample JSON data one to insert the record in DB and another to update the same record in DB.

Insert RequestJSON Data

{
firstName” : “First”,
middleName” : “Middle”,
lastName” : “Last”,
mobileNo” : “9876543210”,
email” : “[email protected]”,
panNo” : “SDSDF1007M”
}

Update Request – JSON Data

{
userId” : 1,
firstName” : “First_Change”,
middleName” : “Middle”,
lastName” : “Last”,
mobileNo” : “9876543210”,
email” : “[email protected]”,
panNo” : “SDSDF1007M”
}

Embedded ID Concept

Let’s take a scenario where in the table you have more than one primary key. Then when your own repository is extending JpaRepository<Model class name, data type of Primary Key>, it will not be possible. So for this comes the concept of Embedded Id.

Example – Let’s say an Employee table where the primary keys are employee_id, employee_email and pan_card. All data types are of varchar. Now when you try to create the repository of Employee Model you are not able to do that. Because the 2nd argument for JpaRepository takes only data type of the primary key and in this case there are 3 primary keys. In this scenario, we need to use the concept of Embedded Id.

Create a class named as EmployeePk.java (you can name anything but a logical name)

@Embeddable
public classEmployeePk {
      @Column(name = "EMPLOYEE_ID")
      private String employeeId;
      @Column(name = "EMPLOYEE_EMAIL")
      private String employeeEmail;
      @Column(name = "PAN_CARD")
      private String panCard;
}

Now define the actual model class Employee.java as:

@Entity
@Table(name = "EMPLOYEE")
public classEmployee {
      @EmbeddedId
      privateEmployeePk employeePk;
      @Column(name = "EMPLOYEE_NAME")
      private String employeeName;
      @Column(name = "EMPLOYEE_MOBILE")
      private String employeeMobile;
}

Then in the Repository Interface, the implementation will be:

@Repository
public interfaceEmployeeRepository extends JpaRepository<Employee, EmployeePk>{}

So, here you can see that the data type of the Primary Key used here is the Embedded Id data type.

Download the Source Code from GitHub

Common Faced Problems

Spring Data Problems

Interview FAQs

Spring Data Interview FAQs

Spring Data using NoSQL DB and Spring REST

Spring Data using Cypher Neo4j DB and Spring REST

Spring Data using Redis and Spring REST

Other Useful Links

Spring REST

Spring RabbitMQ

Spring Apache Kafka – Producer & Consumer

Spring Kafka Confluent – Set Up

Spring Kafka Confluent – Producer & Consumer

Spring Apache Kafka Connect

Spring Mongo Kafka Connector

Spring Cloud using Google Cloud SQL & Google Cloud Storage

Spring Cloud using Google Cloud Pub-Sub

Spring Cloud using Google Cloud Spanner

Spring Reactive Web Flux Programming