beginner~2h

Spring Data JPA & Hibernate

"Just extend JpaRepository and you get CRUD for free" is true and also hides a lot. This module is what's actually running underneath that one line of interface declaration.

Learning objectives

  • Beginner: State what JpaRepository actually generates for you, and recognize that Hibernate — not magic — is doing the SQL translation underneath.
  • Intermediate: Write derived query methods correctly and know when a method name is too complex for that convention.
  • Advanced: Justify why ddl-auto=update/create is unsafe in production and what a real migration strategy replaces it with.
LayerWhat it is
JPA (Jakarta Persistence API)A specification — a set of interfaces and annotations (@Entity, @Id) — with no implementation of its own.
HibernateThe actual ORM engine implementing the JPA spec — translates your entity operations into real SQL, tracks changes, manages the persistence context.
Spring Data JPAA higher-level abstraction on top of JPA/Hibernate — generates repository implementations (§08.3) so you rarely touch the JPA API directly.

Spring Boot auto-configures all three together the moment spring-boot-starter-data-jpa is on the classpath (Module 04 §4) — Hibernate as the JPA provider, a DataSource /connection pool, and Spring Data JPA's repository infrastructure.

@Entity @Table(name = "books") public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String title; private String author; @CreationTimestamp private Instant createdAt; // getters/setters (or Lombok — see Module 07's pitfall on entities) }

💻 Code example

@Entity @Table(name = "books") public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String title; private String author; @CreationTimestamp private Instant createdAt; // getters/setters (or Lombok — see Module 07's pitfall on entities) }
public interface BookRepository extends JpaRepository<Book, Long> { // save(), findById(), findAll(), deleteById() all come free from JpaRepository }

◆ Under the hood — how a method-less interface does anything

At startup, Spring Data JPA scans for interfaces extending JpaRepository and generates a dynamic proxy implementation for each one — you never write or see this implementation class; it's created via Java's dynamic proxy mechanism and registered as a bean by the container itself, exactly like any other bean from Module 03.

💻 Code example

public interface BookRepository extends JpaRepository<Book, Long> { // save(), findById(), findAll(), deleteById() all come free from JpaRepository }

Spring Data JPA can generate a full query implementation just from a method's name, parsing keywords like findBy, And, OrderBy to build the underlying query — no SQL or JPQL required for common cases.

public interface BookRepository extends JpaRepository<Book, Long> { List<Book> findByAuthor(String author); List<Book> findByAuthorAndTitleContainingIgnoreCase(String author, String titleFragment); List<Book> findByCreatedAtAfterOrderByCreatedAtDesc(Instant since); }

▲ Pitfall

Derived query method names get unwieldy fast, and a typo in the method name (referencing a field that doesn't exist) fails at application startup, not compile time — Spring Data parses and validates these method names when building the repository proxy. For anything beyond 2–3 conditions, prefer an explicit @Query annotation with JPQL for readability.

@Query("SELECT b FROM Book b WHERE b.author = :author AND b.createdAt > :since") List<Book> findRecentByAuthor(@Param("author") String author, @Param("since") Instant since);

💻 Code example

public interface BookRepository extends JpaRepository<Book, Long> { List<Book> findByAuthor(String author); List<Book> findByAuthorAndTitleContainingIgnoreCase(String author, String titleFragment); List<Book> findByCreatedAtAfterOrderByCreatedAtDesc(Instant since); }
ddl-auto valueBehavior
noneHibernate never touches the schema — you manage it entirely yourself (or via a migration tool).
validateHibernate checks the schema matches your entities at startup, failing fast if not, but never modifies it.
updateHibernate adds missing tables/columns automatically — convenient in local dev, risky elsewhere.
create-dropDrops and recreates the entire schema on every startup/shutdown — for tests only.

▲ Pitfall

ddl-auto=update in a production environment is a well-known real-world incident source: Hibernate's auto-migration is a best-effort heuristic, not a reviewed, reversible migration — it can silently make unexpected schema changes as your entities evolve, with no rollback path. Production systems should use validate (or none) paired with a dedicated migration tool (Flyway or Liquibase) that gives you versioned, reviewable SQL migration scripts instead.

✓ Quick recap

What's the relationship between JPA, Hibernate, and Spring Data JPA? JPA is a specification; Hibernate is the implementation that does the real ORM work; Spring Data JPA is a higher-level abstraction generating repository implementations on top of both. When does a typo in a derived query method name actually fail? At application startup, when Spring Data JPA parses and validates the method name while building the repository proxy — not at compile time. Why is ddl-auto=update discouraged in production? It's a best-effort, unreviewed schema change with no rollback path — versioned migration tools like Flyway give reviewable, reversible changes instead.

Want a visual for this concept?

Generate a diagram tailored to “Spring Data JPA & Hibernate” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.

Sign in to generate a visual →

Practice quiz

Next Step

Continue to Relationships & Queries← Back to all Spring Boot chapters