Spring Data JPA Tutorial

Spring Data JPA

Spring Data JPA Tutorial

Spring Data JPA Example

Spring Data JPA CRUD Example

Spring Data JPA vs Hibernate

Spring Data JPA Interview Questions

What is Spring Data JPA?

Spring Data JPA makes it easier to work with JPA providers. A JPA provider is an object relational mapping (ORM) tool that implements the JPA specification. The JPA specification defines how Java objects represent relational database tables.

Spring Data JPA is an abstraction for working with JPA providers such as Hibernate. Using Spring Data JPA, you can avoid the boilerplate code associated with managing transactions and entity managers for providers like Hibernate.

What's in this tutorial?

In this Spring Data JPA tutorial, see how to create a Spring Boot app that manages a one-to-many relationship between authors and books using Spring Data JPA and MySQL.

1. Creating the project

You can easily create a project with all the necessary dependencies using maven.


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">


spring-boot-starter-data-jpa includes dependencies for Hibernate and Spring Data JPA abstractions.

mysql-connector-java includes the MySQL database driver for connecting to a datasource.

2.Configuring the database

Spring provides abstractions that hide the implementation details of connecting to a MySQL instance. Specifying the following in application.properties configures Spring Data JPA to work with the database:


spring.datasource.username=<DATABASE USERNAME>
spring.datasource.password=<DATABASE PASSSWORD>
spring.jpa.database-platform = org.hibernate.dialect.MySQL55Dialect
spring.jpa.hibernate.ddl-auto = create

3. Create the entities

Entities are classes that map to tables in the database. For each table in the database, you can create a corresponding entity class:

Author Entity

package bookservice.model;

import javax.persistence.*;
import java.util.Set;

public class Author {
    private Long id;

    private String firstName;

    private String lastName;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "author")
    private Set books;

    protected Author() {}

    public Author(String first, String last) {
        this.firstName = first;
        this.lastName  = last;

    public Set getBooks(){
        return this.books;

    public String getFullName(){
        return this.firstName + " " + this.lastName;

Book Entity


package bookservice.model;

import javax.persistence.*;

public class Book {
    private Long id;

    @ManyToOne(fetch = FetchType.EAGER)
    private Author author;

    private String title;

    protected Book() {}

    public Book(String title){
        this.title = title;

    public String getTitle(){
        return this.title;

    public void setAuthor(Author author){
        this.author = author;

    public Author getAuthor(){
        return this.author;


The @Entity annotation specifies a class corresponds to a table in the database. Each member of the class corresponds to a column in the database. For example, the author table will have a column first_name and last_name.

You can override default column names via @Column. This annotation allows you to specify optional name and constraints/validations like uniqueness and required.

The @Id annotation signifies a class member is the primary key for that table. This is often used in combination with @GeneratedValue to automatically manage id generation for you.

Managing relationships between entities

Notice the use of @OneToMany and @ManyToOne. These annotations specify a one-to-many association between authors and books. One author can have many books.

This type of relationship requires the book table have a foreign key referencing the author table. In this sense, the book table "owns the relationship".

To achieve this relationship, @OneToMany is used to associate a set of books with an author. The mappedBy = "authors" attribute points to the associated field on the owning entity in the relationship. For these reasons, the @ManyToOne annotation is used on the author field for Book.

FetchType.EAGER vs FetchType.LAZY

Notice how a FetchType is specified for each one-to-many annotation. This indicates whether associated data will be eagerly or lazily loaded. Lazy loading can save memory and processing as associated records are only retrieved when asked for. Eager loading can be better if associated data will always be accessed by the application.

4. Create the repositories

Repositories are how the application interacts with the database. Extending Spring Data JPA interfaces like CrudRepository allows for an easy data access layer implementation.

Author Repository


package bookservice.repository;

import bookservice.model.Author;
import org.springframework.data.repository.CrudRepository;

public interface AuthorRepository extends CrudRepository {

Book Repository

package bookservice.repository;

import bookservice.model.Book;
import org.springframework.data.repository.CrudRepository;

public interface BookRepository extends CrudRepository {
    Book findByTitle(String title);

Notice how by simply extending the CrudRepository interface is enough to implement a basic data access layer between your application and the database. Supplying the entity and id type <Author, Long> is enough for Spring Data to automatically implement the beans necessary to perform CRUD operations on the database.

But how is this possible?

When @EnableJpaRepositories is specified (by default with later versions of Spring), Spring automatically implements JPA repositories based on these interfaces. This includes repository methods like:





You can also define your own method signatures:

Book findByTitle(String title);

Based on the method signature Spring can implement the necessary methods for running this query.

5. Running the application



package bookservice;

import bookservice.model.Author;
import bookservice.model.Book;
import bookservice.repository.AuthorRepository;
import bookservice.repository.BookRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

public class Application {

    private static final Logger log =

    public static void main(String[] args){
        SpringApplication.run(Application.class, args);

    public CommandLineRunner demo(BookRepository bookRepo, AuthorRepository authRepo) {
        return (args) -> {
            //create a new author
            Author author = new Author("JK", "Rowling");
            //create a new book
            Book book = new Book("Harry Potter");
            //save author to db
            //associate author with book
            //save book
            //read book from db with custom findByTitle
            Book savedBook = bookRepo.findByTitle("Harry Potter");
            //print title
            //print book author's full name

Notice how CommandLineRunner is used to run some code after the @SpringBootApplication starts. After creating a new book and author, the saved author is associated with the new book via:


When we save the book, the foreign key column will populate for author_id.

Finally, we can fetch the saved book with our custom findByTitle() book repo method. Since the author is eagerly loaded, we can directly access the author and log the full name without a session.

Your thoughts?