Introduction to Spring Data JPA
Spring Data JPA is a project from large Spring family. It helps to reduce the amount of code by easy implementation of JPA (Java Persistence API) based repositories. Its main feature is automatic creation of repository implementations at runtime.
Before starting development developer should be familiar with:
- Java
- Spring Core
- Relational databases terms
- JPA
- Maven or Gradle
Set up
In this project we will configure Spring Data JPA by Maven Spring Boot Starter Data Starter JPA dependency.
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-data-jpa</artifactid>
<version>2.1.10.RELEASE</version>
</dependency>
In the real project we need to configure database connection details in application properties files adequately to the used environment. An example of one of such configurations:
spring.datasource.url=database-url
spring.datasource.username=username
spring.datasource.password=password
In my project I used in-memory h2 database by adding embedded h2 Maven dependency.
<dependency>
<groupid>com.h2database</groupid>
<artifactid>h2</artifactid>
<scope>runtime</scope>
<version>1.4.199</version>
</dependency>
I created table and inserted records in data.sql file which was automatically detected and executed.
Model
Learner entity was created with below code.
@Table(name = "learner")
@Entity
public class Learner {
@Id
private Integer id;
@Column
private String name;
@Column
private String birthCity;
@Column
private int age;
Configuration of repository
Spring Data JPA automatically creates repository implementations from a repository interface. For this purpose LearnerRepository extends CrudRepository with type arguments: entity class and the type of its ID. CrudRepository is a basic available repository, it doesn`t support adding, sorting and pagination’the findAll default method. You need to extend PagingAndSortingRepository with type arguments: entity class and type of its ID to have this possibility.
public interface LearnerRepository extends CrudRepository<learner, integer=""> {
public interface LearnerPagingAndSortingRepository extends PagingAndSortingRepository<learner, integer=""> {
Default available methods
CrudRepository and PagingAndSortingRepository offer default methods such as: findAll, findAllById, findById, deleteAll, deleteById, save, saveAll.
Define other query methods
You can define your own query methods by declaring their method signature with keywords and field names. You can use the feature to find and delete queries. A query can be built with one or more conditions, with and/or logical operators. It’s possible to use options like :
- first matching record
- concrete number of matching records
- field contains/ends/begins some keyword
- greater/smaller/in interval
- matching regex
- sorting
Learner findFirstByAgeBetween(int firstAge, int secondAge);
List<learner> findAllByName(String name);
List<learner> findAllByNameContains(String partOfSurname);
List<learner> findAllByNameEndingWithAndBirthCityContains(String endOfName, String partOfBirthCityName);
List<learner> findAllByNameOrAge(String name, int age);
List<learner> findAllByNameOrAgeOrderByBirthCity(String name, int age);
List<learner> deleteAllByAgeGreaterThan(int age);
Querying with @Query
Spring Data JPA offers possibility for querying with JPQL or SQL. On example below is used JPQL with annotation @Query for updating Learners which have proper name. @Modifying annotation is used with @Query for ensuring that update, delete, insert operations will execute.
@Modifying
@Query("update Learner set emailAddress = :newEmailAddress where name = :name")
void updateAllEmailAddressesWhereName(@Param("name") String name, @Param("newEmailAddress") String newEmailAddress);
An example usage of native SQL query is shown below.
@Query(value = "SELECT * FROM LEARNER l WHERE l.age = 14", nativeQuery = true)
List<learner> findAllLearnersWhereAgeEqualFourteen();
Sorting
You can sort results by Sort object with one or more specified variables. Sorting can be done in ascending or descending order. Repositories which extends CrudRepository are having possibility of use sorting only for newly created methods. Method findAllByName was added with Sort object to LearnerRepository, when method is invoked we need to provide specified sorting as shown in example below.
List<learner> findAllByName(String name, Sort sort);
learnerRepository.findAllByName("Ana", Sort.by("age").ascending()));
learnerRepository.findAllByName("Ana", Sort
.by("age").ascending()
.and(Sort.by("emailAddress").descending()));
LearnerPagingAndSortingRepository which extends PagingAndSortingRepository gives availability of putting Sort object into findAll method as shown below.
learnerPagingAndSortingRepository.findAll(Sort.by("name")));
Pagination
Pagination can be added by creation of PageRequest object which is implementation of Pageable interface. Similar to sorting adding pagination depends from type of Repository extended by our interface. For LearnerRepository we need to add Pageable object to interface method declaration.
List<learner> findAllByName(String name, Pageable pageable);
learnerRepository.findAllByName("Karolina",PageRequest.of(0, 3)));
LearnerPagingAndSortingRepository extends PagingAndSortingRepository, so we can use directly Pageable object in default findAll method. Default method findAll returns Page object, so we need to use its get() method to get Stream to be able to do next operations.
learnerPagingAndSortingRepository.findAll(PageRequest.of(0, 4)).get();
Pagination and sorting together
There is possibility of using pagination and sorting together. It is possible by creation of Pageable object. Example usage of LearnerRepository with its invocation.
List<learner> findAllByName(String name, Pageable pageable);
learnerRepository.findAllByName("Karolina",
PageRequest.of(0, 3, Sort.by("birthCity").ascending())));
Example usage of LearnerPagingAndSortingRepository with sorting first by name, second sorting by birthCity.
learnerPagingAndSortingRepository.findAll(PageRequest.of(0, 7, Sort.by("name").ascending().and(Sort.by("birthCity").ascending()))).get();
Summary
Spring Data JPA provides us features which simplify developers work and reduce amount of code needed. It enables easy access to relational databases with good coding standard principles. Spring Data JPA is easy to learn and start development.