Spring Boot JpaRepository Example

Learn to Spring Data JPA module and work with JpaRepository interface for performing the CRUD operations in underlying databases in a Spring Boot application.

1. JpaRepository Interface

The JpaRepository interface is the core interface of Spring Data JPA, providing basic CRUD (Create, Read, Update, Delete) operations for entities. It provides key methods such as save(), findById(), findAll(), and deleteById() etc.

The following are the parent interfaces of the JpaRepository interface and it extends the features of all these interfaces.

Interface NameDescription
CrudRepository<T, ID>Provides basic CRUD (Create, Read, Update, Delete) operations for entities.
ListCrudRepository<T, ID>Extends CrudRepository and provides additional methods for batch operations on entities.
ListPagingAndSortingRepository<T, ID>Extends ListCrudRepository and adds support for pagination and sorting of query results.
PagingAndSortingRepository<T, ID>Provides methods for pagination and sorting of query results.
QueryByExampleExecutor<T>Allows execution of JPA Criteria API queries represented as Example objects, providing a way to define example criteria.

2. Configuring JpaRepository in Spring Boot

Let us follow the process of configuring the JpaRepository in a step-by-step fashion:

Step 1: Maven

To enable the Spring Data JPA module, we must add the following dependency in the project:

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

Additionally, we can include an in-memory database for quickstart setup and executing the unit tests.

<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <scope>runtime</scope>
</dependency>

The equivalent gradle dependency is:

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-data-jpa',
  runtimeOnly 'com.h2database:h2'
}

Step 2. JPA Entity

The next step is to create the JPA @Entity which will be persisted in the database.

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.Instant;

@Entity
@Table(name = "PERSON")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  Long id;
  String firstName;
  String lastName;
  Instant createdAt;
}

Step 3. Create Repository Interface by Extending JpaRepository

Next, we create a new interface in the application that extends the JpaRepository interface. We can use any specialized interface (as listed in the first section) based on our requirements.

import com.howtodoinjava.jpaRepository.demo.model.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;

public interface PersonRepository extends JpaRepository<Person, Long> {
  //...
}

The best part of using a JpaRepository (or other interfaces) is that we can define custom methods that can perform more complex queries or operations that are not covered by the default methods.

In the following example, we are adding some queries on the column name “firstName” and applying different conditions to it.

public interface PersonRepository extends JpaRepository<Person, Long> {

  List<Person> findByFirstNameLike(String firstNamePart);
  List<Person> findByFirstNameLikeIgnoreCase(String firstNamePart);
  
  List<Person> findByFirstNameContaining(String firstNamePart);

  List<Person> findByFirstNameStartsWith(String firstNameStart);
  List<Person> findByFirstNameEndsWith(String firstNameEnd);

  List<Person> findByFirstNameStartsWithIgnoreCase(String firstNameStart);
  List<Person> findByFirstNameEndsWithIgnoreCase(String firstNameEnd);
}

Step 4. Configure DataSource

The easiest way to configure a datasource in the Spring boot application is by defining the properties as follows. We can configure any database by changing the values of the following properties.

spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=TRUE;TRACE_LEVEL_FILE=3
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

Step 5. Configuring Database Schema and Initial Data

The next step is to configure the database schema and seed initial data into it, if required. This is done through using the following SQL files:

  • schema.sql: contains the DDL statements that create the database tables and other objects.
  • data.sql: contains the DML statements that insert the seed data into tables.
create table person
(
    id         bigint primary key AUTO_INCREMENT,
    first_name varchar not null,
    last_name  varchar not null,
    created_at timestamp
);
truncate table person;
insert into person(first_name, last_name, created_at) values
    ('Alex','Kolen', CURRENT_TIMESTAMP),
    ('Brian','Schultz', CURRENT_TIMESTAMP),
    ('Charles','Dave', CURRENT_TIMESTAMP),
    ('David','Freezer', CURRENT_TIMESTAMP),
    ('Edvin','Shaw', CURRENT_TIMESTAMP);

Step 6. Test the Application

Now, we can start the application and verify the whole configuration. The @SpringBootApplication annotation enables the auto-configuration feature which in turn scans the JpaRepository and its sub-interfaces and other required beans to interact with the database.

@SpringBootApplication
public class Application {
  public static void main(String[] args) {

    SpringApplication.run(Application.class, args);
  }
}

Check out the console logs:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.2.4)

...c.h.jpaRepository.demo.Application       : Starting Application using Java 21-ea with PID 11164 (...\target\classes started by user in C:\Users\user\IdeaProjects\Spring-Data-Examples)
...c.h.jpaRepository.demo.Application       : No active profile set, falling back to 1 default profile: "default"
...s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 52 ms. Found 1 JPA repository interface.
...com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
...com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:3939be71-3f9f-403d-b667-07360736f82d user=SA
...com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
...o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
...org.hibernate.Version                    : HHH000412: Hibernate ORM core version 6.4.4.Final
...
...o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
...j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
...c.h.jpaRepository.demo.Application       : Started Application in 3.451 seconds (process running for 4.421)

Step 7: JUnit Tests

Finally, we can setup the test infrastructure by adding ‘spring-boot-starter-test‘ module and writing some testcases.

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

The Spring boot provides the @DataJpaTest annotation for a JPA test that focuses only on JPA components. This annotation disables the full auto-configuration and instead applies only configuration relevant to JPA tests.

The @Sql annotation helps in populating the database with test data before executing the test.

import com.howtodoinjava.jpaRepository.demo.model.Person;
import com.howtodoinjava.jpaRepository.demo.repository.PersonRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.jdbc.Sql;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;

@DataJpaTest
@Sql("/data.sql")
public class PersonRepositoryTest {

  @Autowired
  PersonRepository repository;

  @Test
  void findAllPersons_should_pass() {

    List<Person> persons = repository.findAll();
    assertThat(persons).isNotEmpty();
    assertThat(persons).hasSize(5);
  }
}

3. Conclusion

This short Spring Boot tutorial discussed the steps to configure the JpaRepository interface and database access functionality in a Spring Boot application. We learned to configure the repository, schema files, and datasource and finally tested the application using JUnit tests.

Happy Learning !!

Source Code on Github

Comments

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.