Spring Data JPA

About

Spring Data JPA is a part of the larger Spring Data family. It is a framework that:

  • Simplifies the implementation of data access layers using JPA (Java Persistence API).

  • Reduces the amount of boilerplate code for repository classes.

  • Provides ready-to-use CRUD, pagination, sorting, query creation without writing any SQL/JPAQL manually (unless needed).

  • Integrates seamlessly with Hibernate (or any other JPA provider).

Spring Data JPA = Spring + JPA (Hibernate or others) + Repository Abstraction + Query Generation

Why Spring Data JPA?

Traditional JPA (or Hibernate) involves a lot of repetitive code:

EntityManager em = entityManagerFactory.createEntityManager();
Employee emp = em.find(Employee.class, id);

Spring Data JPA abstracts and automates these things by just providing an interface. Example:

public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

No need to manually open/close EntityManager, no manual queries for basic operations.

Components of Spring Data JPA

Component
Description

Repository Interfaces

Abstractions like JpaRepository, CrudRepository, PagingAndSortingRepository for different functionalities.

Query Methods

Define methods in interfaces; Spring Data JPA automatically generates queries based on method names.

Custom Queries

Create your own JPQL/SQL queries using @Query.

Specifications

Build dynamic, type-safe queries.

Projections

Fetch only required data instead of entire entity.

Auditing

Automatic tracking of entity creation, modification timestamps.

Pagination & Sorting

Built-in support for pageable results.

Transactional Support

Integrated with Spring’s @Transactional management.

Commonly Used Spring Data JPA Interfaces

Interface
Purpose

CrudRepository<T, ID>

Basic CRUD operations: save, find, delete.

PagingAndSortingRepository<T, ID>

Extends CrudRepository; adds paging and sorting features.

JpaRepository<T, ID>

Extends PagingAndSortingRepository; adds JPA-specific operations like batch delete, flush, etc.

JpaSpecificationExecutor<T>

Execute dynamic queries using JPA Criteria API (Specifications).

QueryByExampleExecutor<T>

Query entities based on example instances.

How Spring Data JPA Works Internally

When we define a simple repository interface like:

public interface EmployeeRepository extends JpaRepository<Employee, Long> { }

Spring Data JPA automatically provides the implementation of this interface at runtime — we do not have to implement it manually.

Step
Action

1

Spring Boot scans for Repository Interfaces during startup.

2

A Proxy (Dynamic Implementation) of the repository is created.

3

Proxy uses JpaRepositoryFactory to produce repository beans.

4

Proxy internally uses an EntityManager to perform operations.

5

Method names are parsed and converted into JPA Queries automatically.

6

Transactional behavior is automatically managed.

Step 1: Component Scanning

  • Spring Boot auto-configures JPA when it detects spring-boot-starter-data-jpa in the classpath.

  • It scans the package and sub-packages for interfaces extending JpaRepository, CrudRepository, or other repository markers.

The scan happens using annotations like:

@EnableJpaRepositories(basePackages = "com.example.repository")

Or if we don't explicitly configure it, Spring Boot auto-detects based on the location of your @SpringBootApplication class.

Step 2: Repository Proxy Generation

  • Spring uses a dynamic proxy (JDK Dynamic Proxy or CGLIB Proxy) to create a runtime implementation of your repository interface.

  • This proxy does not contain any handwritten logic; instead, it delegates calls to the correct logic.

The key class responsible is: org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean

This class creates a JpaRepositoryFactory, which then builds a repository proxy.

Step 3: EntityManager Injection

  • Every generated repository proxy is injected with a JPA EntityManager.

  • EntityManager is the main API for persisting, finding, updating, and removing entities in JPA.

JpaEntityInformation (meta-information about the entity) is also associated with each repository.

So when we call save(), findById(), etc., the proxy simply delegates to methods on EntityManager like:

entityManager.persist(entity);
entityManager.find(Entity.class, id);

Step 4: Parsing Method Names into Queries

If we define a method like:

List<Employee> findByDepartment(String department);

Spring Data JPA:

  • Parses method name (findByDepartment)

  • Creates JPQL query:

SELECT e FROM Employee e WHERE e.department = :department

This parsing is powered by: org.springframework.data.repository.query.parser.PartTree

Spring does not require you to write the query manually unless it’s too complex.

Step 5: Executing Custom Queries

When we add:

@Query("SELECT e FROM Employee e WHERE e.department = :dept")
List<Employee> fetchByDepartment(@Param("dept") String department);

Spring Data JPA detects the @Query annotation and uses it instead of parsing the method name.

The execution pipeline is handled by SimpleJpaQuery or custom QueryLookupStrategy.

Step 6: Transaction Management

  • By default, Spring Data JPA repositories operate inside a transactional context.

  • The methods like save(), delete(), etc., are automatically transactional.

  • Spring Boot configures transaction management using @EnableTransactionManagement.

If needed, we can override by putting @Transactional(readOnly = true) on repository methods.

Key Internal Classes Involved

Class
Purpose

JpaRepositoryFactoryBean

Responsible for creating repository proxies.

JpaRepositoryFactory

Creates repository implementations dynamically.

SimpleJpaRepository

Default implementation of repository logic.

EntityManager

Core JPA component for persistence operations.

PartTree

Parses query methods into JPQL.

QueryLookupStrategy

Strategy interface for looking up queries (derived, annotated, or named queries).

Example Internal Flow

Suppose we have this repository:

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

The behind-the-scenes flow will be:

Step
What Happens

1

Spring Boot scans and finds EmployeeRepository.

2

JpaRepositoryFactoryBean creates a dynamic proxy.

3

Proxy is linked to an EntityManager.

4

You call findByName("John").

5

Proxy parses method → generates JPQL → binds parameter "John".

6

Query is executed via EntityManager under a transactional context.

7

Result (List of Employees) is returned to you.

Last updated

Was this helpful?