Spring Boot and JPA Example
Are you keen on learning about using Spring Boot with JPA? Yes? Gather your tools and read on. This example is very straight forward and simple, it should be easy to understand. Let’s begin with our Spring Boot JPA example.
You can also check this tutorial in the following video:
1. Tools
2. Assumptions
This article assumes that you know your way around Eclipse. You are familiar with Maven. Familiarity with SQL statements is handy but not required. Basically, you have done some coding. This project has been created using Eclipse Mars so all instructions are based on this IDE.
3. Project Setup
To start, we create our project. This can be done by going to File -> New -> Maven Project and fill up what is required. Alternatively, we can import the Maven project by going to File -> Import… and picking the project.
4. Project Object Model
Our pom.xml
should look like the one below:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.javacodegeeks.example</groupId> <artifactId>spring-boot-jpa</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
As shown above, our project has 2 dependencies. We are using spring-boot-starter-data-jpa
which means that we can use all the Spring modules included in it. For example, the Spring Core and Spring Data JPA modules will be available for us to use plus many more. The next dependency is the H2 Database Engine. We will be utilizing H2’s in-memory database for this example. In Eclipse, we can see the dependency hierarchy by opening the pom.xml
and clicking on the Dependency Hierarchy tab.
The Spring Boot Maven plugin enables us to package the project as an executable jar.
5. Define an Entity
We need to create a Movie
object and annotate it as a JPA entity. This object represents a row in the movie table.
Movie.java
package com.javacodegeeks.example; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Movie { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String title; private String description; protected Movie() { } public Movie(String title, String description) { this.title = title; this.description = description; } public Long getId() { return id; } public String getTitle() { return title; } public Movie setDescription(String description) { this.description = description; return this; } public String getDescription() { return description; } @Override public String toString() { return "Movie [id=" + id + ", title=" + title + ", description=" + description + "]"; } }
The default constructor exists for JPA and we won’t use it directly. The public constructor is what we’ll use to create instances of Movie
to be saved to the database.
The id
field is annotated with @Id
and GeneratedValue
to indicate that it is the object’s ID and to indicate that the ID should be generated automatically.
The title
and description
fields are assumed to map to columns in the movie table with the same name.
6. Create a Repository Interface
We extend the CrudRepository
interface to take advantage of Spring Data’s JPA features. Spring Data JPA focuses on using JPA to store data in a relational database and it has the ability to create repository implementations automatically.
MovieRepository.java
package com.javacodegeeks.example; import java.util.List; import org.springframework.data.repository.CrudRepository; public interface MovieRepository extends CrudRepository<Movie, Long> { List<Movie> findByTitle(String title); }
The generic parameters that CrudRepository
works with are of type Movie
and Long
. Because we extended CrudRepository
, we inherit several methods for working with Movie
persistence. We are able to create, read, update, and delete Movie
entities.
We have also defined our own query method by simply declaring their method signature (findByTitle
).
7. Code Walkthrough
Our code below performs the four basic operations of persistent storage. That is create, read, update, delete, in short CRUD. Skim through the code below but peruse the explanation after it.
Main.java
package com.javacodegeeks.example; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Main implements CommandLineRunner { @Autowired private MovieRepository movieRepo; public static void main(String[] args) { SpringApplication.run(Main.class, args); } public void run(String... args) throws Exception { System.out.println("\nCreating 3 movie records..."); movieRepo.save(new Movie("Mr. Deeds", "Comedy")); movieRepo.save(new Movie("Mad Max Fury Road", "Science Fiction")); movieRepo.save(new Movie("We Were Soldiers", "War")); readRecords(); System.out.println("\nUpdating Mad Max Fury Road record..."); List<Movie> movies = movieRepo.findByTitle("Mad Max Fury Road"); Movie madMax = movies.get(0); madMax.setDescription("Action/Adventure"); movieRepo.save(madMax); readRecords(); System.out.println("\nDeleting Mr. Deeds record..."); movies = movieRepo.findByTitle("Mr. Deeds"); Movie mrDeeds = movies.get(0); movieRepo.delete(mrDeeds); readRecords(); } private void readRecords() { System.out.println("Reading movie records..."); System.out.printf("%-30.30s %-30.30s%n", "Title", "Description"); for (Movie movie : movieRepo.findAll()) { System.out.printf("%-30.30s %-30.30s%n", movie.getTitle(), movie.getDescription()); } } }
Instead of annotating our class with @Configuration
, @EnableAutoConfiguration
, and @ComponentScan
, we use the @SpringBootApplication
annotation as a convenient alternative. This annotation tells Spring Boot to scan for other components, add beans based on the classpath, and tags the class as a source of bean definitions.
We implemented the CommandLineRunner
because we want to execute the run
method after the application context is loaded.
Spring Boot automatically creates a MovieRepository
because of the @Autowired
annotation.
The main
method uses SpringApplication.run()
to run the application.
Walking through the run
method, we first added the movie records using the save
method. Did you notice that we did not need to create a table for the records? This was done automatically behind the scenes.
We then used the findAll
method to retrieve all the movies in the table. The records are then printed in a nice column.
To update a record, we searched for it based on its title then modify the movie object and saved it back to the repository. The old movie record is overwritten.
The delete
method is used for deleting movie records. Similar to the update operation, we searched for the movie based on its title then used that movie object as the argument to the delete
method. That movie row is removed from the table.
Did you notice that we did not use any SQL statement? Isn’t that neat? Quickly compare the code above with the Spring Boot JDBC Example. Did you see the difference?
8. Spring Boot JPA Output
After running the code above (Run As -> Java Application), we should have an output that looks like the one below.
Console Output
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.5.9.RELEASE) 2018-02-17 10:42:52.576 INFO 3464 --- [ main] com.javacodegeeks.example.Main : Starting Main on asus_k43s with PID 3464 (D:\javacodegeeks_com\spring-boot-jpa\spring-boot-jpa\target\classes started by jpllosa in D:\javacodegeeks_com\spring-boot-jpa\spring-boot-jpa) 2018-02-17 10:42:52.582 INFO 3464 --- [ main] com.javacodegeeks.example.Main : No active profile set, falling back to default profiles: default 2018-02-17 10:42:52.696 INFO 3464 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@1cab0bfb: startup date [Sat Feb 17 10:42:52 GMT 2018]; root of context hierarchy 2018-02-17 10:42:56.728 INFO 3464 --- [ main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default' 2018-02-17 10:42:56.767 INFO 3464 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [ name: default ...] 2018-02-17 10:42:56.916 INFO 3464 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.0.12.Final} 2018-02-17 10:42:56.919 INFO 3464 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found 2018-02-17 10:42:56.922 INFO 3464 --- [ main] org.hibernate.cfg.Environment : HHH000021: Bytecode provider name : javassist 2018-02-17 10:42:57.201 INFO 3464 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.1.Final} 2018-02-17 10:42:57.517 INFO 3464 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect 2018-02-17 10:42:59.764 INFO 3464 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000227: Running hbm2ddl schema export 2018-02-17 10:42:59.797 INFO 3464 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000230: Schema export complete 2018-02-17 10:42:59.869 INFO 3464 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2018-02-17 10:43:01.055 INFO 3464 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup Creating 3 movie records... Reading movie records... Title Description 2018-02-17 10:43:01.370 INFO 3464 --- [ main] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory Mr. Deeds Comedy Mad Max Fury Road Science Fiction We Were Soldiers War Updating Mad Max Fury Road record... Reading movie records... Title Description Mr. Deeds Comedy Mad Max Fury Road Action/Adventure We Were Soldiers War Deleting Mr. Deeds record... Reading movie records... Title Description Mad Max Fury Road Action/Adventure We Were Soldiers War 2018-02-17 10:43:01.898 INFO 3464 --- [ main] com.javacodegeeks.example.Main : Started Main in 10.558 seconds (JVM running for 11.902) 2018-02-17 10:43:01.900 INFO 3464 --- [ Thread-3] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1cab0bfb: startup date [Sat Feb 17 10:42:52 GMT 2018]; root of context hierarchy 2018-02-17 10:43:01.901 INFO 3464 --- [ Thread-3] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown 2018-02-17 10:43:01.903 INFO 3464 --- [ Thread-3] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2018-02-17 10:43:01.903 INFO 3464 --- [ Thread-3] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000227: Running hbm2ddl schema export 2018-02-17 10:43:01.910 INFO 3464 --- [ Thread-3] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000230: Schema export complete
The output shows the CRUD operations being performed. We created 3 movie records. We read the movie records from the in-memory database. After that, we updated the “Mad Max Fury Road” description, changing it from “Science Fiction” to “Action/Adventure”. Then we deleted the “Mr. Deeds” movie record. Easy peasy lemon squeezy.
9. Spring Boot JPA Summary
In summary, we include the spring-boot-starter-data-jpa
dependency to make available all the Spring modules we need to make JPA operations. We then add the database dependency, in this case H2. We define a JPA entity, in this case a Movie
class. Next, we created a repository interface by extending Spring’s CrudRepository
. Finally, we wire everything up in the main application class.
10. Download the Source Code
This is an example about Spring Boot JPA.
You can download the source code of this example here: spring-boot-jpa.zip.