Spring Data JPA Example

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

In this Spring Data JPA example, see how a one-to-many relationship is implemented between two relational tables book and author.


Think of entities as tables in your database. For each table you can create an entity class whose members represent the table's columns.

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;


@Entity signifies the class represents a table in the database.

@Id signifies the member is the primary key for this table.

@GeneratedValue means the id should be automatically generated. This means you don't have to worry about generating the id yourself.

@Column adds optional metadata for a given entity member. Using @Column, you can specify name, implement constraints (unique, nullable, etc).

@OneToMany and @ManyToOne specify the association between the two tables. An owner of the association is defined via mappedBy = "author" pointing to the field on the owning side of the relationship (in this case Book).

What's FetchType?

A FetchType is also specified. While FetchType.EAGER loads associated records at the time data is accessed, FetchType.LAZY only loads associated records when they are explicitly accessed by the application.

FetchType.LAZY saves memory and processing but FetchType.EAGER makes sense if the associated data is always being used by the application.


Repositories are the gateway to interacting with the database. By simply extending Spring Data JPA defined interfaces, you can quickly perform CRUD operations without boilerplate code.

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);

Extending the CrudRepository along with specifying the entity and id type <Book, Long> is enough to generate repositories. Spring automatically creates the beans from these interfaces as long as @EnableJpaRepositories is specified. This happens by default with newer versions of Spring Boot and no configuration is necessary.

Note you can also define your own query method signatures similar to findByTitle(String title). Spring Data JPA automatically implements the interface based on the signatures you provide.

Running the example...



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

Your thoughts?