Quick Start | Spring Data JPA
Quick Start Using Maven
1) Including Maven Dependencies in pom.xml
pom.xml
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.4.5
com.example
spring-data-jpa-examples
0.0.1-SNAPSHOT
spring-data-jpa-examples
Demo project for Spring Boot
11
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
This includes all of the libraries you'll need to work with Spring Data JPA including:
spring-boot-starter-data-jpa: Includes libraries for Hibernate, the JPA specification, JDBC, and spring-data-jpa itself.
mysql-connector-java: This is required dependency for MySQL implementation. It's the MySQL connector library for Java.
spring-boot-starter-test: This includes libraries for testing Spring Boot applications.
2) Installing Maven Dependnecies
To install the dependencies listed in the pom.xml simply run:
mvn install
To package the application into an executable file run:
mvn package
3) Add Entities
Entities are classes you define that represent tables in the MySQL database. Let's create an authors entity and a books entity. This will help with relationship examples (OneToMany, ManyToMany):
Author.java
package com.example.springdatajpaexamples;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
public class Author {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
private String name;
protected Author() {}
public Author(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Book.java
package com.example.springdatajpaexamples;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
public class Book {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
private String title;
protected Book() {}
public Book(String title) {
this.title = title;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
@Entity tells JPA this class represents a table in the database. The class members(id, name) represent columns in the database.
@Id tells JPA this is the primary key for this table.
@GeneratedValue specifies how the primary key gets generated for new entries. GenerationType.AUTO is the default strategy. This strategy delegates to the JPA provider (Hibernate) for optimally generating unique ids.
4) Add Repositories
By simply extending JPA Repository interfaces, Spring Data JPA provides methods for accessing the database:
AuthorRepository.java
package com.example.springdatajpaexamples;
import org.springframework.data.repository.CrudRepository;
public interface AuthorRepository extends CrudRepository {
}
BookRepository.java
package com.example.springdatajpaexamples;
import org.springframework.data.repository.CrudRepository;
public interface BookRepository extends CrudRepository {
}
By simply defining interfaces for our entities, Spring Data automatically manages collection items for the corresponding tables.
Confused? Check out our starter Spring Data JPA guide for in depth explanations.
5) Configure application.properties
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/example
spring.datasource.username=root
spring.datasource.password=
This defines connection details for our MySQL instance. You'll notice we are connecting to a local instance of MySQL for this example.
6) Run the example
SpringDataJpaExampleAmmplication.java
package com.example.springdatajpaexamples;
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;
import java.util.Optional;
@SpringBootApplication
public class SpringDataJpaExamplesApplication {
private static final Logger log = LoggerFactory.getLogger(SpringDataJpaExamplesApplication.class);
public static void main(String[] args) {
SpringApplication.run(SpringDataJpaExamplesApplication.class, args);
}
@Bean
public CommandLineRunner demo(AuthorRepository authorRepo, BookRepository bookRepo) {
return (args) -> {
Author author = new Author("Sam Erickson");
authorRepo.save(author); //saves author to database
Optional result = authorRepo.findById(author.getId()); //find one from db
if(result.isPresent()) {
System.out.println(result.get().getName());
}
};
}
}
Using the CommandLineRunner, we can test our entity classes.
PLEASE NOTE: Spring Data transactions work best inside @Service and HTTP Requests. Since Spring Data automatically handles Hibernate sessions, entity managers, etc. you can get unexpected results when not running Spring Data inside Spring Application Context.
Spring Data JPA Examples
findOne()
Note* The findOne() method was replaced by the findById() in newer version of Spring Data CrudRepository implementation. While you can still use findOne() method, it has been repurposed for QueryByExample querying technique. As a result, findById() is the preferred method for retrieving a single entity from the database:
Author author = new Author("Sam Erickson");
authorRepo.save(author); //saves author to database
Optional result = authorRepo.findById(author.getId()); //find one from db
if(result.isPresent()) {
System.out.println(result.get().getName());
}
Notice how the authorRepo returns an Optional. For this reason, we check to make sure the result returned something via result.isPresent(). We then unwrap the optional via get().
Join Examples
A JOIN table combines two or more tables based on related columns. JOIN tables are used in cases where an author has many books and/or a book has many authors...
@OnetoOne
To create a one to one relationship between Books and Authors (one author has one book), modify the entity classes for Book and Author:
Author.java
//
@OneToOne
private Book book;
public Book getBook(){
return this.book;
}
public void setBook(Book book){
this.book = book;
}
//
Book.java
//
@OneToOne(mappedBy= "book")
private Author author;
public Author getAuthor() {
return this.author;
}
public void setAuthor(Author author) {
this.author = author;
}
//
The @OneToOne annotation is used on both entities. Since the relationship must have an owner side, we specify mappedBy="book" on the Book entity. This results in the authors table having a column book_id.
To see the relationship in action:
Author author = new Author("Sam Erickson");
Book book = new Book("Mastering the Tech Interview");
bookRepo.save(book);
author.setBook(book);
authorRepo.save(author); //saves author to database
Optional result = authorRepo.findById(author.getId()); //find one from db
if(result.isPresent()) {
Author savedAuthor = result.get();
System.out.println(savedAuthor.getBook().getTitle());
}
@OneToMany
To create a one to many relationship (one author having many books), modify the Book and Author entities:
Author.java
//
@OneToMany(mappedBy="author")
private Set books = new HashSet();
public Set getBooks(){
return this.books;
}
public void setBooks(Set books){
this.books = books;
}
//
Book.java
//
@ManyToOne
private Author author;
public Author getAuthor() {
return this.author;
}
public void setAuthor(Author author) {
this.author = author;
}
//
Since an author can have many books, we define a Set of books with the @OneToMany annotation. The mappedBy="author" indicates the book table will own the relationship.
To run the example...
Author author = new Author("Sam Erickson");
Book book = new Book("Mastering the Tech Interview");
Book book2 = new Book("My Second Masterpiece");
Set books = new HashSet();
books.add(book);
books.add(book2);
author.setBooks(books);
authorRepo.save(author); //saves author to database
bookRepo.save(book);
bookRepo.save(book2);
Author savedAuth = authorRepo.findById(author.getId()).get(); //find one from db
savedAuth.getBooks().forEach(b -> {
System.out.println(b.getTitle());
});
This will ultimately create a author_id on the books table in the database.
@ManyToMany
To create a many to many relationship (many books having many authors) modify the Book and Author class with the following:
Author.java
//
@ManyToMany(mappedBy="authors")
private Set books = new HashSet();
public Set getBooks(){
return this.books;
}
public void setBooks(Set books){
this.books = books;
}
//
Book.java
@ManyToMany
@JoinTable(
name = "BOOK_AUTHOR",
joinColumns = @JoinColumn(name = "book_id", referencedColumnName="id"),
inverseJoinColumns = @JoinColumn(name = "author_id", referencedColumnName="id")
)
private Set authors;
public Set getAuthors() {
return this.authors;
}
public void setAuthors(Set authors) {
this.authors = authors;
}
We specify the @ManyToMany annotation on both entities. Notice how we specify the @JoinTable only on the Book entity. This will generate a book-author table in the database.
To see the example in action...
Author author = new Author("Sam Erickson");
Author author2 = new Author("Ted Krinshaw");
Book book = new Book("Mastering the Tech Interview");
Book book2 = new Book("My Second Masterpiece");
Set authors = new HashSet();
Set books = new HashSet();
authors.add(author);
authors.add(author2);
books.add(book);
books.add(book2);
author.setBooks(books);
author2.setBooks(books);
book.setAuthors(authors);
book2.setAuthors(authors);
authorRepo.save(author);
authorRepo.save(author2);//saves author to database
bookRepo.save(book);
bookRepo.save(book2);
Author savedAuth = authorRepo.findById(author.getId()).get(); //find one from db
savedAuth.getBooks().forEach(b -> {
System.out.println(b.getTitle());
});