Introduction to Spring Data JPA

Last Updated : 2 Apr, 2026

Spring Data JPA is a framework that simplifies database access in Spring Boot applications by providing an abstraction layer over the Java Persistence API (JPA). It enables seamless integration with relational databases using Object-Relational Mapping (ORM), eliminating the need for boilerplate SQL queries.

With Spring Data JPA, developers no longer need to:

  • Manually write DAO implementations.
  • Manage EntityManager directly.
  • Write repetitive CRUD queries

Key Features of Spring Data JPA

  • Repository Abstraction: Spring Data JPA provides interfaces like JpaRepository to perform CRUD operations without writing SQL queries.
  • Query Methods: We can define methods like findByName() or findByAgeGreaterThan() and Spring automatically generates the query.
  • Pagination and Sorting: Supports pagination and sorting using built-in methods like findAll(Pageable pageable).
  • Custom Queries: Allows writing custom queries using @Query annotation (JPQL or native SQL).
  • Integration with JPA: Works with JPA providers like Hibernate to map Java objects to database tables.

Core Components

  • Entity -> Represents a table in the database
  • Repository -> Interface for database operations
  • Service Layer -> Contains business logic
  • JPA Provider -> Implementation (e.g., Hibernate)

Steps to Build a Spring Boot Application with JPA

Step 1. Create the project

1. Use Spring Initializr or your IDE:
2. Fill the following Details:

  • Project: Maven
  • Language: Java
  • Spring Boot: 3.x (any modern 3.x release)
  • Java: 17 (or 21)

3. Add following Dependencies:

  • Spring Web
  • Spring Data JPA
  • H2 Database (for quick testing)

4. Project Structure:

After creating the project, Add the following classes then the folder structure will be like below:

Project Structure

Step 2. pom.xml

If using Maven, ensure these dependencies (Initializr will generate them). Example snippet (dependencies only)

XML
<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>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
  </dependency>

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

Step 3. Configure datasource (H2 quick setup)

Configure database datasource inside src/main/resources/application.properties:

application.properties:

Java
# H2 config (in-memory)
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver

# JPA / Hibernate
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

# H2 console (optional)
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

Step 4. Defining the Entity Class

Let us see the key important files in the project. Starting with POJO class

GeekUserRecord.java:

Java
package com.gfg.model;

import jakarta.persistence.*;

@Entity
@Table(name = "geek_user")
public class GeekUserRecord {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String email;
    private String gender;
    private Integer numberOfPosts;

    public GeekUserRecord() {}

    // Getters & setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

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

    public String getGender() { return gender; }
    public void setGender(String gender) { this.gender = gender; }

    public Integer getNumberOfPosts() { return numberOfPosts; }
    public void setNumberOfPosts(Integer numberOfPosts) { this.numberOfPosts = numberOfPosts; }
}

Explanation: Represents a database table using a Java class. Annotations like @Entity, @Table, @Id map the class and fields to table and columns. It is used by JPA to store and retrieve data.

Step 5. REST Controller

Let us see the controller file now.

GeekUserController.java:

Java
package com.gfg.controller;

import com.gfg.model.GeekUserRecord;
import com.gfg.service.GeekUserService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api")               // base path
public class GeekUserController {

    private final GeekUserService userService;

    public GeekUserController(GeekUserService userService) {
        this.userService = userService;
    }

    // GET /api/users
    @GetMapping("/users")
    public List<GeekUserRecord> getAllUser() {
        return userService.getAllGeekUsers();
    }

    // POST /api/users
    @PostMapping("/users")
    public ResponseEntity<GeekUserRecord> addUser(@RequestBody GeekUserRecord userRecord) {
        GeekUserRecord saved = userService.addGeekUser(userRecord);
        return ResponseEntity.status(HttpStatus.CREATED).body(saved);
    }
}

Explanation: Handles HTTP requests and exposes REST APIs. It receives client requests, calls the service layer, and returns responses. Annotations like @GetMapping and @PostMapping define API endpoints.

Step 6. Service layer

Let us see the service file.

GeekUserService.java:

Java
package com.gfg.service;

import com.gfg.model.GeekUserRecord;
import com.gfg.repository.GeekUserRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional
public class GeekUserService {

    private final GeekUserRepository repository;

    public GeekUserService(GeekUserRepository repository) {
        this.repository = repository;
    }

    public List<GeekUserRecord> getAllGeekUsers() {
        return repository.findAll();
    }

    public GeekUserRecord addGeekUser(GeekUserRecord userRecord) {
        return repository.save(userRecord);
    }
}

Explanation: Contains business logic and interacts with the repository layer. It processes data before sending it to the controller or database. @Transactional ensures safe database operations.

Step 7. Creating the Repository Interface

Now we need to add a repository interface and it should extend CrudRepository.

GeekUserRepository.java:

Java
package com.gfg.repository;

import com.gfg.model.GeekUserRecord;
import org.springframework.data.jpa.repository.JpaRepository;

public interface GeekUserRepository extends JpaRepository<GeekUserRecord, Long> {
    // add custom finder methods if needed, e.g.List<GeekUserRecord> findByName(String name);
}

Explanation: Acts as the data access layer by extending JpaRepository. It provides built-in CRUD methods like save(), findAll() without writing SQL. Spring automatically generates query implementations.

Step 8. Main application class

Now, we need to execute this program and check the output. For that, we need to run the below file

SpringDataJPAExampleApplication.java:

Java
package com.gfg;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringDataJPAExampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringDataJPAExampleApplication.class, args);
    }
}

Running and Testing the Application

Right-click on the main class and run the file as a Java application, we can see the output in the console.

Output:

Console-Output
Running and Testing the Application

Initially as there are no records, when we hit http://localhost:8080, we won't be seeing any data. Let's add the data by adding via the Postman client. Postman client has to be installed for doing this operation. URL to add users: http://localhost:8080/add-geekuser (Remember that this URL matches the controller file requestmapping).

Output

Now a user is added. Hence we can verify the same by using http://localhost:8080

JPA vs Hibernate

JPA

Hibernate

It is a Java specification for mapping relational data in Java application. It is not a frameworkHibernate is an ORM framework and in that way data persistence is possible.
In JPA, no implementation classes are provided.In Hibernate, implementation classes are provided.
Main advantage is It uses JPQL (Java Persistence Query Language) and it is platform-independent query language.Here it is using HQL (Hibernate Query Language).
It is available under javax.persistence package. It is available under org.hibernate package.
In Hibernate, EclipseLink, etc. we can see its implementation.Hibernate is the provider of JPA.
Persistence of data is handled by EntityManager.Persistence of data is handled by Session.
Comment

Explore