Spring Data JPA: Entities and Repositories

Introduction

Spring Data JPA maps Java objects to database tables and generates query methods from method names—less SQL boilerplate than JDBC for CRUD-heavy apps. This chapter adds JPA to a Spring Boot 3 project, defines entities and repositories, and compares when to choose JPA versus MyBatis.

Prerequisites

Add Dependencies

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
 
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
</dependency>

PostgreSQL: use org.postgresql:postgresql instead of MySQL driver.

Configure JPA

application.yml:

ddl-autoBehavior
noneNo schema changes—production default
validateCheck schema matches entities
updateDev-friendly—adds columns/tables
create-dropRecreate on each restart—tests only

Warning

Do Not Use update/create-drop in Production

Use migrations (Flyway/Liquibase) for controlled schema changes.

Define an Entity

Code explanation:

  • @Entity marks a persistent class
  • @Table maps to DB table name
  • GenerationType.IDENTITY matches MySQL AUTO_INCREMENT

Repository Interface

java
package com.example.demo.user;
 
import org.springframework.data.jpa.repository.JpaRepository;
 
import java.util.Optional;
 
public interface UserRepository extends JpaRepository<User, Long> {
 
    Optional<User> findByEmail(String email);
 
    boolean existsByEmail(String email);
}

Code explanation:

  • JpaRepository provides save, findById, delete, pagination
  • Method name findByEmail generates WHERE email = ? query

Service Layer

REST Controller

Test:

bash
curl -X POST http://localhost:8080/api/users \
  -H "Content-Type: application/json" \
  -d '{"email":"ada@example.com","displayName":"Ada"}'

Pagination and Sorting

Repository:

java
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
 
Page<User> findByDisplayNameContainingIgnoreCase(String keyword, Pageable pageable);

Service call:

java
Page<User> page = userRepository.findByDisplayNameContainingIgnoreCase(
    "a",
    PageRequest.of(0, 10, Sort.by("createdAt").descending())
);

JPA vs MyBatis

Choose JPAChoose MyBatis
CRUD-heavy domainsComplex SQL, reports
Rapid prototypingDBA-tuned SQL control
Object graphs with relationshipsLegacy SQL migration

Many teams use JPA for simple domains and MyBatis for heavy queries—both can coexist with clear boundaries.

See MySQL track for SQL fundamentals.

FAQ

LazyInitializationException?

Access lazy associations inside @Transactional service method or use DTO projection.

Entity returned from REST exposes too much?

Map to DTO or use @JsonIgnore on sensitive fields.

Table not created?

Check ddl-auto, DB credentials, and entity @Entity scan in main package.

Hibernate SQL dialect wrong?

Usually auto-detected; set spring.jpa.database-platform only when needed.

Replace MyBatis entirely?

Not required—pick per module or phase.

Connection pool same as JDBC chapter?

Yes—JPA uses same DataSource and HikariCP.