Introduction

Spring Data JPA has become an integral part of Java development, offering a simplified and efficient way to interact with databases.
In this comprehensive tutorial, I will guide you through the process of setting up a Spring Data JPA project from scratch, defining repository and entity and perform CRUD operations.
Whether you prefer Maven or Gradle, understanding the basics and advanced features of Spring Data JPA is essential for modern application development.

Table of Contents

What is Spring Data JPA

In any application, getting data efficiently is super important.
Spring Data JPA is a sub-project of spring framework and is very helpful in working with databases in Java much easier.
JPA, short for Java Persistence API, is like a set of rules that help us manage how Java objects connect with databases.
And when we use it with the Spring framework, it becomes even more awesome for developers to handle databases smoothly.

Advantages of Spring Data JPA

  1. Makes Data Connection Simple
    Spring Data JPA makes it easy to connect Java code with databases.
  2. No More Repetitive Code
    Normally, dealing with databases in Java involves writing a lot of similar code.
    Spring Data JPA takes away most of that boilerplate code, so developers can focus on writing business logic rather than doing repetitive things.
  3. Database independent
    If we decide to use a different database, Spring Data JPA helps us make that switch without causing too much trouble.

Getting Started With Spring Data JPA

In this section, we will set up our development environment to get started with spring data jpa.
This involves creating a spring boot project in IDE and adding required dependencies.

Creating Spring Boot Project

For creating a spring boot project from scratch, follow this article.

Setup and Configuration

Before diving into the code, you need to add the necessary dependencies to your project.
For Maven, you need to update pom.xml file, while Gradle users will modify the build.gradle file.
These dependencies include the Spring Data JPA library, which simplifies database operations and provides powerful features for data access.

<!-- Maven Dependencies -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- Other dependencies as needed -->
</dependencies>
// Gradle Dependencies
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    // Other dependencies as needed
}

Understanding JPA Repositories

JPA (Java Persistence API) repositories are a feature of the Spring Data JPA framework that provides a convenient way to interact with the database in a Java application.

JPA repositories offer a high-level abstraction over the actual database operations, allowing developers to work with entities and perform CRUD (Create, Read, Update, Delete) operations without writing boilerplate code for data access.

Repository Pattern Explained

The Repository pattern is a design pattern that encapsulates a class that encapsulates data and the operations on the data.
The repository is a central place to access the data, and it acts as a gateway to the data, providing a single point of contact for interacting with the data layer.

Enabling Repositories

For using repositories, first you need to enable them and tell spring boot where they reside in your codebase.

This is done using @EnableJpaRepositories annotation over a configuration class or the main class that has @SpringBootApplication annotation.

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

@Configuration
@EnableJpaRepositories(basePackages = "com.codippa.repository")
public class Config {
    // Other configuration if needed
}

In this example, it tells Spring boot to scan the package com.codippa.repository and its sub-packages for JPA repositories.

Defining Repository

Spring Data JPA repository is an interface and it is defined by extending an appropriate interface.

The most commonly extended interface is JpaRepository as shown below.

import org.springframework.data.jpa.repository.JpaRepository;

public interface EmployeeRepository extends JpaRepository<Employee, Long> {
    // Custom query methods if needed
}

Database Configuration

Configuring database implies providing parameters so that spring boot application can connect to the database.

There are different ways to provide these parameters as explained below.

1. application.properties

Add following properties to application.properties file

spring.datasource.url=jdbc:mysql://localhost:3306/dbName
spring.datasource.username=userName
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect

2. application.yml

If you are using application.yml instead of application.properties, then provide following properties

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/dbName
    username: userName
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQLDialect

These files would be present in src/main/resources folder.

3. Code Configuration

You can also configure database in application code by creating a configuration class as below

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

@Configuration
public class DatabaseConfig {

  @Bean
  public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setUrl("jdbc:mysql://localhost:3306/dbName");
    dataSource.setUsername("userName");
    dataSource.setPassword("password");
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    return dataSource;
  }
}

Notice that this class has @Configuration annotation, since it a configuration class.

You can learn different ways to configure a database in spring boot here.

Defining Entity Classes

Entity classes in Spring Data JPA represent the structure of your database tables.

I will guide you through creating these classes and mapping them to corresponding database tables using annotations.
This step is fundamental for establishing a strong foundation for your data model.

Below is an example of an entity class that represents an employee.

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "employee")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

    // Other fields, getters, and setters
}

To make a class as entity, we use @Entity annotation over the class.

Each entity is mapped to a database table and the name of database table is defined with @Table annotation followed by the table name.

@Id annotation indicates that the field id is the primary key for the entity. In a database table, the primary key uniquely identifies each record.

`@GeneratedValue(strategy = GenerationType.IDENTITY) annotation, used in conjunction with @Id, specifies the strategy for generating values for the primary key.
In this case, it uses the “IDENTITY” strategy, which typically relies on an auto-incremented column in the database.

Field names or instance variables of entity class correspond to database table columns and to link a field to database column, @Column annotation is used.

Remember that in entity classes, we used javax.persistence classes and not org,hibernate classes.
This is because javax.persistence classes provide a consistent and standard API for working with databases in Java. This standardization simplifies the learning curve and makes it easier for developers to switch between different JPA implementations.

Hibernate is an implementation of JPA specification.

CRUD Operations with Spring Data JPA

Assuming you have the Employee entity as defined above, here’s an example of how you can perform CRUD (Create, Read, Update, Delete) operations using Spring Data JPA.

Inserting New Data(Create)

To create a new employee, you can use the save method provided by the Spring Data JPA CrudRepository or JpaRepository.

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

@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository employeeRepository;

    public Employee createEmployee(Employee employee) {
        return employeeRepository.save(employee);
    }
}

Note that save() method is implicitly defined in the repository, you don’t need to define it anywhere.

This is the power of Spring Data JPA.

Reading and Querying Data

To retrieve employees, you can use methods provided by CrudRepository or JpaRepository.
Examples include findAll(), findById(), or custom query methods.

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

@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository employeeRepository;

    public List<Employee> getAllEmployees() {
        return employeeRepository.findAll();
    }

    public Optional<Employee> getEmployeeById(Long id) {
        return employeeRepository.findById(id);
    }

    // Custom query method
    public List<Employee> getEmployeesByName(String name) {
        return employeeRepository.findByName(name);
    }
}

Again findAll() and findById() methods are implicitly defined in the repository.

To fetch entity using any of its field, you need to declare(ONLY declare) the method in repository and its implementation will be handled by Spring Data JPA.

So, in above example, we need to add a method findByName() in the repository interface as shown below

import org.springframework.data.jpa.repository.JpaRepository;

public interface EmployeeRepository extends JpaRepository<Employee, Long> {
   Employee findByName(String name);
}

To fetch entity based on any field, simply declare a method prefixed with findBy followed by the field name and a corresponding argument type, Spring Data JPA will do the rest.

Updating Existing Data

To update an existing employee, retrieve the entity, modify its fields, and then save it again using the save() method.

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

@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository repository;

    public Employee updateEmployee(Long id, Employee updatedEmployee) {
        Employee existingEmployee = repository.findById(id)
                .orElseThrow(() -> new RuntimeException("Employee not found with id: " + id));

        existingEmployee.setName(updatedEmployee.getName());
        // Update other fields as needed

        return repository.save(existingEmployee);
    }
}

save() method is used to update and save.
Spring Data JPA infers the type of operation intended based on the value of primary key in the entity.
If the primary key field is null, then it will save and if it is non-null, then update will be performed.

Deleting Data

To delete an employee, you can use the deleteById method or other delete methods provided by CrudRepository or JpaRepository.

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

@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository employeeRepository;

    public void deleteEmployee(Long id) {
        employeeRepository.deleteById(id);
    }
}

deleteById() method is implicitly defined in Spring Data JPA repository.
As such, you are not required to write it anywhere.

Conclusion

In conclusion, mastering Spring Data JPA is an indispensable skill in the toolbox of any Java developer aiming to create robust, efficient, and maintainable data access layers.
The seamless integration with Spring’s ecosystem, its repository-centric design for data access, and the powerful abstraction over database interactions make Spring Data JPA an excellent choice for enterprise-grade applications.

I hope this comprehensive tutorial has equipped you with the knowledge to take your projects to the next level.