Spring Data JPA Introduction

2 minute read

Spring Data JPA eliminates boilerplate database code. Write an interface, Spring generates the implementation.


JPA, Hibernate, and Spring Data JPA

Spring Data JPA    ← High-level abstraction (interfaces)
      │
   Hibernate       ← JPA implementation (ORM)
      │
     JDBC          ← Low-level database communication
      │
   Database        ← PostgreSQL, MySQL, H2, etc.
Layer Role
JPA Specification (standard API for ORM)
Hibernate Implementation of JPA
Spring Data JPA Removes boilerplate — repositories from interfaces

Setup

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>
spring:
  datasource:
    url: jdbc:h2:mem:bookstoredb
    driver-class-name: org.h2.Driver
    username: sa
    password:
  h2:
    console:
      enabled: true
      path: /h2-console
  jpa:
    hibernate:
      ddl-auto: create-drop
    show-sql: true
    properties:
      hibernate:
        format_sql: true

Visit http://localhost:8080/h2-console and connect with JDBC URL jdbc:h2:mem:bookstoredb.


Your First Entity

@Entity
@Table(name = "books")
public class Book {

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

    @Column(nullable = false, length = 200)
    private String title;

    @Column(nullable = false)
    private String author;

    @Column(unique = true, length = 17)
    private String isbn;

    private BigDecimal price;

    @Column(name = "published_date")
    private LocalDate publishedDate;

    @CreationTimestamp
    private LocalDateTime createdAt;

    @UpdateTimestamp
    private LocalDateTime updatedAt;

    // Default constructor required by JPA
    protected Book() {}

    public Book(String title, String author, String isbn, BigDecimal price) {
        this.title = title;
        this.author = author;
        this.isbn = isbn;
        this.price = price;
    }

    // getters and setters...
}

Your First Repository

public interface BookRepository extends JpaRepository<Book, Long> {
    // That's it! Spring generates the implementation
}

You instantly get:

Method SQL Equivalent
save(book) INSERT / UPDATE
findById(1L) SELECT WHERE id = 1
findAll() SELECT *
findAll(pageable) SELECT with LIMIT/OFFSET
deleteById(1L) DELETE WHERE id = 1
count() SELECT COUNT(*)
existsById(1L) SELECT EXISTS

Using the Repository

@Service
public class BookService {

    private final BookRepository bookRepository;

    public BookService(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    public List<Book> findAll() {
        return bookRepository.findAll();
    }

    public Book findById(Long id) {
        return bookRepository.findById(id)
            .orElseThrow(() -> new ResourceNotFoundException("Book", id));
    }

    public Book create(CreateBookRequest request) {
        Book book = new Book(
            request.title(), request.author(),
            request.isbn(), request.price()
        );
        return bookRepository.save(book);
    }
}

ddl-auto Options

Value Behavior Use
create-drop Create on start, drop on stop Dev/testing
create Create on start (drop existing) Dev
update Alter tables to match entities Dev (risky)
validate Validate schema, don’t change Production
none Do nothing Production (use Flyway)

Production: always use validate or none with Flyway/Liquibase for migrations.


Key Takeaways

  1. Spring Data JPA = JPA + Hibernate + auto-generated repositories.
  2. Extend JpaRepository<Entity, IdType> — get CRUD for free.
  3. H2 is perfect for development — in-memory, zero setup.
  4. Use create-drop for dev, validate for production.
  5. Always define a protected no-arg constructor for JPA entities.

What’s Next?

Next: JPA Entities and Repositories — @Entity, @Table, @Id, column mappings, and repository methods.

Updated: