Enterprise Java

Spring Data JPA Example with Spring Boot

1. Introduction

In this post, we shall demonstrate how to leverage the powerful Spring Data JPA APIs to interact with the database, in-memory H2 database for this lesson.

Spring Data JPA offers a set of very powerful and highly-abstracted interfaces which are used to interact with any underlying database. Databases can be MySQL, MongoDB, Elasticsearch or any other supported database. Other advantages for Spring Data JPA include:

  • Support to build extended repositories based on JPA Convention
  • In-built pagination support and dynamic query execution
  • Support for XML based entity mapping

In this example, we will make use of H2 in-memory database. The choice for the database should not affect the Spring Data definitions we will construct as this is the main advantage Spring Data JPA offers. It enables us to completely separate the Database queries from the application logic.

2. Project Setup

We will be using one of the many Maven archetypes to create a sample project for our example. To create the project execute the following command in a directory that you will use as workspace:

mvn archetype:generate -DgroupId=com.javacodegeeks.example -DartifactId=JCG-SpringDataJPA-example -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

If you are running maven for the first time, it will take a few seconds to accomplish the generate command because maven has to download all the required plugins and artifacts in order to make the generation task.

JPA Project Setup using Maven

Notice that now, you will have a new directory with the same name as the artifactId inside the chosen directory. Now, feel free to open the project in your favourite IDE.

Finally, instead of using an IDE to make this project, we used a simple maven command. This helps us to make project setup and initialisation free from any specific IDE you may use.

3. Maven Dependencies

To start with, we need to add appropriate Maven dependencies to our project. We will add the following dependency to our pom.xml file:

pom.xml

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.5.10.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <java.version>1.8</java.version>
</properties>

<dependencies>

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
  </dependency>
  
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
  
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>

Find the latest Spring related dependencies here.

Note that we have also added the H2 database dependency here as well with its scope as runtime as the H2 data is washed away as soon as the application has stopped. In this lesson, we will not focus on how H2 actually works but will restrict ourself to Spring Data JPA APIs. You may also see how we can Configure Embedded H2 Console With a Spring Application.

4. Project Structure

Before we move on and start working on the code for the project, let’s present here the projet structure we will have once we’re finished adding all code to the project:

Project Structure

We have divided the project into multiple packages so that the principle of separation of concern is followed and code remains modular.

5. Defining the Model

We will start by adding a very simple model in our project, a Person. Its definition will be very standard, like:

Person.java

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Person {

    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //standard getters and setters

    @Override
    public String toString() {
        return String.format("Person{id=%d, name='%s', age=%d}", id, name, age);
    }
}

We omitted standard getters and setters for brevity but they are necessary to be made as Jackson uses them during Serialization and Deserialization of an Object.

The @Entity annotation marks this POJO as an object which will be managed by the Spring Data APIs and its fields will be treated as table columns (unless marked transient).

Finally, we added a custom implementation for the toString() method so that we can print related data when we test our application.

6. Defining JPA Repository

JPA provides us with a very simple way of defining a JPA Repository interface.

Before getting to know how to define a JPA Repository, we need to remember that each JPA interface is only made to interact with a single Entity of Database Table when JPA-related functionality is leveraged. We will understand this deeply if we have a look at the interface definition:

PersonRepository.java

import com.javacodegeeks.jpaexample.model.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
}

Although above interface definition is empty, we still have some points which we need to understand:

  • @Repository annotation marks this interface as a Spring Bean which is initialised on application startup. With this annotation, Spring takes care of managing exception database interaction throws gracefuly
  • We used Person as a parameter to signify that this JPA interface will manage the Person Entity
  • Finally, we also passed the data type Long as a parameter. This signifies that the Person Entity contains a unique identifier which is of the type Long

7. Making Service interface

In this section, we will define a service interface which will act as a contract for the implementation and represnet all the actions our Service must support. These actions will be related to making a new user and getting information related to the objects in database.

Here is the contract definition we will be using:

PersonService.java

import com.javacodegeeks.jpaexample.model.Person;
import java.util.List;

public interface PersonService {

    Person createPerson(Person person);
    Person getPerson(Long id);
    Person editPerson(Person person);
    void deletePerson(Person person);
    void deletePerson(Long id);
    List getAllPersons(int pageNumber, int pageSize);
    List getAllPersons();
    long countPersons();
}

We have mentioned all four CRUD operations in this contract along with concept of Pagination.

A paginated API is important to make when we introduce getting all objects from the database based on a pageSize and a pageNumber. The pageSize attribute signifies the number of objects which are fetched from the database whereas the pageNumber attribute act as skip part of the query. For detailed lesson on how Pagination works in Spring, read this lesson.


 

8. Providing Service implementation

We will use the above interface definition to provide its implementation so that we can perform CRUD operations related to the Person Entity we defined earlier. We will do it here:

PersonServiceImpl.java

import com.javacodegeeks.jpaexample.model.Person;
import com.javacodegeeks.jpaexample.repository.PersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class PersonServiceImpl implements PersonService {

    @Autowired
    private PersonRepository personRepository;

    @Override
    public Person createPerson(Person person) {
        return personRepository.save(person);
    }

    @Override
    public Person getPerson(Long id) {
        return personRepository.findOne(id);
    }

    @Override
    public Person editPerson(Person person) {
        return personRepository.save(person);
    }

    @Override
    public void deletePerson(Person person) {
        personRepository.delete(person);
    }

    @Override
    public void deletePerson(Long id) {
        personRepository.delete(id);
    }

    @Override
    public List<Person> getAllPersons(int pageNumber, int pageSize) {
        return personRepository.findAll(new PageRequest(pageNumber, pageSize)).getContent();
    }

    @Override
    public List<Person> getAllPersons() {
        return personRepository.findAll();
    }

    @Override
    public long countPersons() {
        return personRepository.count();
    }
}

It is positively surprising that all the method implementations are only one line of code. This shows the level of abstraction JPA Repositories provide to us.

Most of the operations above are simple to understand. Main thing to notice is that we never provided any methods in the Repository we made like getAllPersons() etc! Then how did these methods appeared altogether? The answer, again, lies in the abstraction JPA Repositories provide to us. All of the methods like findAll(), delete(), save(...) etc. are in-built into the JpaRepository we extended in our repository interface definition.

9. Using the CommandLineRunner

To test all the code we have written toll now, along with the database interactionpart, we will be using the CommandLineRunner in our main class of our Spring Boot application. A CommandLineRunner runs right before the main() method for the Spring Boot application is called and so, it is an ideal space to perform any init steps or testing code.

To test the application, we will use a service bean to perform database operations in our class:

pom.xml

import com.javacodegeeks.jpaexample.model.Person;
import com.javacodegeeks.jpaexample.service.PersonService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 DataJpaApp implements CommandLineRunner {

  private static final Logger LOG = LoggerFactory.getLogger("JCG");

  @Autowired
  private PersonService service;

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

  @Override
  public void run(String... strings) {

    LOG.info("Current objects in DB: {}", service.countPersons());

    Person person = service.createPerson(new Person("Shubham", 23));
    LOG.info("Person created in DB : {}", person);

    LOG.info("Current objects in DB: {}", service.countPersons());

    person.setName("Programmer");
    Person editedPerson = service.editPerson(person);
    LOG.info("Person edited in DB  : {}", person);

    service.deletePerson(person);
    LOG.info("After deletion, count: {}", service.countPersons());
  }
}

In above sample code, we just made simple calls to some important methods we created in our service like creating some data and accessing it later method calls.

Now, we will finally run our project using Maven itself (again being independent from any IDE to run our project).

10. Running the Application

Running the application is easy with maven, just use the following command:

Running the Application

mvn spring-boot:run

Once we run the project, we will be seeing the following output:

Data JPA Project Output

As expected, we first created some sample data and confirmed it by calling the count() method call. Finally, we deleted the data and again confirmed it with the count() method call.

11. Download the Source Code

This was an example of with Spring Boot and Spring Data JPA APIs along with the in-memory H2 database.

Download
You can download the full source code of this example here: Spring Data JPA Example

Shubham Aggarwal

Shubham is a Java EE Engineer with about 3 years of experience in building quality products with Spring Boot, Spring Data, AWS, Kafka, PrestoDB.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

9 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
vinod
vinod
6 years ago

Thanks for the tutorial.
In my case I have a data base ready for my application, so can you through some light on how to create a entity class for existing database structure?

Ben
Ben
6 years ago

I downloaded the example code and imported it into Eclipse Oxygen as a Maven project. Immediately I got the following error on the POM.xml file:

Project build error: Non-resolvable parent POM for com.javacodegeeks.example:JCG-SpringDataJPA-Example:1.0-SNAPSHOT: Could not transfer artifact org.springframework.boot:spring-boot-starter-parent:pom:1.5.10.RELEASE from/to central (https://repo.maven.apache.org/maven2): repo.maven.apache.org: unknown error and ‘parent.relativePath’ points at no local POM

Do you know what caused it? Any help will be greatly appreciated.
Thanks!

Santosh Mandadi
Santosh Mandadi
6 years ago

Line 6 in PersonRepository.java
public interface PersonRepository extends JpaRepository {
should be
public interface PersonRepository extends JpaRepository {

Santosh Mandadi
Santosh Mandadi
6 years ago

“JpaRepository “

Santosh Mandadi
Santosh Mandadi
6 years ago

Missing Person,Long after JpaRepository inside angled brackets. Content inside angled brackets is being removed in this blog.

Zbig
Zbig
6 years ago

true, as “We used Person as a parameter to signify that this JPA interface will manage the Person Entity” lacks code

Noelia
Noelia
3 years ago

How can I configure jpa with other database (not in-memory)? Thanks

Back to top button