How to use Pagination and Sorting with Spring Data JPA | Learn Java Skills

Imran Shaikh
2

When retrieving huge amounts of data from a SQL database, the lazy operation is preferable over the eager operation.


You may be required to retrieve a huge amount of data from a SQL database and give it back to the client, and you may be wondering what the performance cost would be if you query a SQL database to retrieve all the data at once.


Yes, you are correct; it is not best practice to query a significant amount of the database to find all the data at once. You may be wondering, what is the ideal approach if the business requirement is to send the entire table of data?


In such scenarios, you have to integrate the concept of pagination or sorting into your application, because even if you return a significant amount of data to your client, it is assumed that your service's users will not use all of the data.


Consider the following e-commerce website: An e-commerce website's backend may have a large quantity of data, yet it only displays a small bit of data at a time. So, if you wish to see additional products, then only they will bring up the next set of products on your screen.


This is what pagination is all about. Fetch the data on demand.


toc
Pagination and Sorting with Spring Data JPA thumbnail image

Dependencies


To use the Spring data JPA in your Spring Boot application, you only need two dependencies. The first is spring-boot-starter-data-jpa, and the second one is about the database you are using. I've utilized MySql throughout this lesson.


Here are more details on Spring Data JPA.


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

 <dependency>
	<groupId>com.mysql</groupId>
	<artifactId>mysql-connector-j</artifactId>
	<scope>runtime</scope>
 </dependency>

Create an entity as well as the repository.


I'm expecting you to have finished configuring your database in your spring boot application. If not, I recommend reading this page to learn how to configure the MySQL database in the spring boot application.


In my MySQL database, I have a table called employee that I'll use to demonstrate pagination and sorting.


I'll make an entity and a repository for this table.


Employee Entity

 package in.learnjavaskills.paginationandsorting.entity;

 import jakarta.persistence.*;

 import java.util.Objects;

 @Entity
 @Table(name = "employee")
 public class Employee
 {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name ="id")
    private Long id;

    @Column(name = "first_name", nullable = false)
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "address")
    private String address;
    // getter and setter, constructor, equal and hashcode, tostring
 }

Employee Repository

 package in.learnjavaskills.paginationandsorting.repository;

 import in.learnjavaskills.paginationandsorting.entity.Employee;
 import org.springframework.data.repository.PagingAndSortingRepository;

 public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long>
 {} 

Here I used the PagingAndSortingRepository interface; you can also use the JpaRepository interface.


The JpaRepository interface extends the ListPagingAndSortingRepository interface and the ListPagingAndSortingRepository interface extends the PagingAndSortingRepository interface.


Pagination with the spring data JPA in the spring boot


Pagination is utilized when we wish to fetch all the data from the database, as was covered earlier in this lesson. We fetch the data chunk by chunk using the pagination idea to enhance performance.


Pageable Interface

The pageable is an interface that offers a number of pagination-related operations.Some of the most widely used methods are as follows:


Method's Description
int getPageSize(); Use the getPageSize method to determine how many pages there are in total
int getPageNumber(); You can obtain the current page by using the getPageNumber method.
Sort getSort(); The getSort method is used for finding the Sort class.
Pageable next(); Use the next method to move to the next Pageable.
Pageable previousOrFirst(); Use the previousOrFirst function to go to the previous or first Pageable.
Pageable first(); The first method is availabe to jump to the first Pageable.
boolean hasPrevious(); To determine whether the previous pageable is available or not, use the hasPrevious method.
Pageable withPage(int pageNumber) By specifying the page number using the withPage method, you can expect the exact pageable.

How do I create an instance of pageable?

To build a pageable instance, we can use the static methods of the PageRequest class.


Let's execute our first pagination program to better understand its operation.


In this example, I'll use the PagingAndSortingRepository interface's findAll method to retrieve the whole set of records from the employee table.


 @Test
 void findAllData()
 {
   Pageable pageable = PageRequest.of(0, 1);
   Page<Employee> page = employeeRepository.findAll(pageable);
   System.out.println("total pages : " + page.getTotalPages());
   if (page.hasContent())
   {
 	 List<Employee> employeeList = page.getContent();
 	 if (Objects.nonNull(employeeList) && !employeeList.isEmpty())
 	   employeeList.forEach(System.out :: println);
   }
 }

As you can see from the example above, we have a repository instance called employeeRepository, and we performed the pagination using the findAll method , which accepts a pageable object.


PageRequest.of() method takes two arguments, which are as follows:
pageNumber: This is a parameter of the int type, and as its name suggests, you must supply it with the page number for which you want to retrieve page data.
pageSize: This option, which is of the int type, asks you to specify how many records to show each page.

To create an instance of the Pageable interface, use the PageRequest.of() function.

(alert-passed)


Sorting with spring data JPA in the spring boot


The Sort class, which is part of the org.springframework.data.domain package, can be used to sort the record.


You can sort your results using any of the numerous overloaded Sort.by() methods that are available, depending on your needs.


As you can see, I sorted the outcome by the employee's first name in ascending order using the sort.by() method.


 @Test
 void sortData()
 {
   Sort sortByFirstNameInAscOrder = Sort.by(Sort.Direction.ASC, "firstName");
   Pageable pageable = PageRequest.of(0, 4, sortByFirstNameInAscOrder);
   Page<Employee> page = employeeRepository.findAll(pageable);
   System.out.println("total pages : " + page.getTotalPages());
   if (page.hasContent())
   {
     List<Employee> employeeList = page.getContent();
     if (Objects.nonNull(employeeList) && !employeeList.isEmpty())
       employeeList.forEach(System.out :: println);
   }
}

Here, I used the Sort by(Direction direction, String... properties) method with the following two arguments:
Direction: The Sort class contains an enum called "Direction." We can use it to specify the sort order we desire, such as ASC for ascending and DESC for descending.
Arrays of String: which accepts the field's name for sorting; in this case, we used the employee's first name.(alert-success)
Sort by(Direction direction, String... properties)(code-box)

Is sorting the direction possible solely using the Direction enum? In addition, you may adjust the sorting direction by using the Sort class's ascending() or descending() method.(alert-passed)
Sort sortByFirstNameInAscOrder = Sort.by("firstName").ascending();
Sort sortByFirstNameInDesOrder = Sort.by("firstName").descending();(code-box)

Is there the ideal way to use sorting without utilizing pagination?

We saw how to sort the result with pagination in the previous example, but are we able to sort the result without using pagination in our application?


Yes, you are correct; we can sort the result in spring data JPA without requiring pagination. We will have the similar experience in the following session.


 @Test
 void sortDataWithoutPagination()
 {
   Sort sortByFirstNameInDesOrder = Sort.by("firstName").descending();
   Pageable pageable = PageRequest.of(0, 4, sortByFirstNameInDesOrder);
   List<Employee> employeeList = (List<Employee>) employeeRepository.findAll(sortByFirstNameInDesOrder);

   if (Objects.nonNull(employeeList) && !employeeList.isEmpty())
	 employeeList.forEach(System.out :: println);
 }

How to use pagination and sorting on the user-defined query


We had previously used the pagination and sorting on the Spring data JPA predefine method, which were provided out of the box.


If you've come this far, you must have wondered about it. It's OK; we can utilize the pagination and sorting on the Spring data JPA's interface function, but what if we need to execute the same pagination and sorting on our own query?


The following section will walk us through how we will be able to do pagination and sorting on the user-defined query.


To allow pagination in your custom query, accept the pageable interface in the abstract method of your repository.


I'm implementing the JPQL query right here in the employee repository. The native query will also work for both queries, or you are able to follow to the exact same process.


You can also learn how to use the DTO project in spring boot with spring data JPA by clicking here.


 package in.learnjavaskills.paginationandsorting.repository;

 import in.learnjavaskills.paginationandsorting.entity.Employee;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.PagingAndSortingRepository;

 public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long>
 {
    @Query("from Employee")
    Page<Employee> findAllEmployee(Pageable pageable);
 }

Once you've finished declaring the abstract method in the repository layer with the pageable interface, you may utilize it exactly as we did earlier in this article in the service layer.


 @Test
 void paginationOnUserDefineMethod()
 {
   Sort sortByFirstNameInDesOrder = Sort.by("firstName").descending();
   Pageable pageable = PageRequest.of(0, 4, sortByFirstNameInDesOrder);
   Page<Employee> page = employeeRepository.findAllEmployee(pageable);
   System.out.println("total pages : " + page.getTotalPages());
   if (page.hasContent())
   {
     List<Employee> employeeList = page.getContent();
     if (Objects.nonNull(employeeList) && !employeeList.isEmpty())
       employeeList.forEach(System.out :: println);
   }
 }

What exactly is the Slice interface? In Spring Data JPA pagination, how do I use the Slice interface?


Slice is an interface in the org.springframework.data.domain package that allows us to get a single slice of data. We've learnt that if we want to use pagination, we can use the page interface as the return type of the result, but you can also use the slice interface instead.


In the Page interface, we must explicitly specify the page number to retrieve the data, whereas in the Slice interface, we simply utilize the hasNext() method to detect whether the next batch is available or not.


You can access the next batch of data using the nextPageable() method once the next batch is available.


In the following part, we'll look at how the slice interface interacts with Pageable.


 package in.learnjavaskills.paginationandsorting.repository;

 import in.learnjavaskills.paginationandsorting.entity.Employee;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.domain.Slice;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.PagingAndSortingRepository;

 public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long>
 {
    @Query("from Employee")
    Slice<Employee> findAllEmployee(Pageable pageable);
 }

Let's look at how the slice interface can be used in the service layer. As previously explained, we must utilize the hasNext() method to verify whether the next batch is accessible and then use nextPageable() to move on to the next batch.


 @Test
 void paginationOnUsingTheSlice()
 {
  Sort sortByFirstNameInDesOrder = Sort.by("firstName").descending();
  Pageable pageable = PageRequest.of(0, 1, sortByFirstNameInDesOrder);
  Slice<Employee> slice = employeeRepository.findAllEmployee(pageable);

  if (slice.hasContent())
  {
    List<Employee> employeeList = slice.getContent();
    if (Objects.nonNull(employeeList) && !employeeList.isEmpty())
      employeeList.forEach(System.out :: println);

    while (slice.hasNext())
    {
      slice = employeeRepository.findAllEmployee(slice.nextPageable());
      employeeList = slice.getContent();
      if (Objects.nonNull(employeeList) && !employeeList.isEmpty())
        employeeList.forEach(System.out :: println);
    }
  }
 }

Slice is an interface in the org.springframework.data.domain package that allows us to get a single slice of data.
The hasContent() method determines whether or not the batch of data is empty.
The hasNext() method is used to see whether the next bacth is available.
The nextPageable() method is used to get the next pageable interface instance in order to get the next batch data.(alert-passed)


What is the key difference between the page interface and the slice interface?


The org.springframework.data.domain package contains both the page interface and the slice interface.


The page interface extends the slice interface, which means that it has all of the capabilities of the slice interface, whereas the slice interface extends the streamable interface.

The page interface includes two additional methods, such as the
getTotalPages(): gets the total number of pages accessible.
getTotalElements(): The total number of elements is returned by getTotalElements().(alert-passed)

The page interface use case

When you wish to display the number of pages available in the user interface (UI), utilize the Page interface. Because you may use the getTotalPages() function to display the number of pages.


for example, at the bottom of the e-commerce website, display the number of pages accessible to browse to the next or previous page or directly jump to the user's chosen page number.


The Slice interface use case

Use the Slice interface when you don't want to show the amount of records in the initial query or when you wish to fetch data on demand, such as on a lazy loading website, such as a social media site, where content is loaded while scrolling or hitting the load button.



Conclussion


We covered how to implement pagination in a Spring Boot application using Spring Data JPA in this instructional article.


We've seen the spring data JPA's default method, which includes pagination by default; however, we've also utilized pagination in a user-defined method or query.


In this post, you will not only learn about pagination, but also about sorting with the Sort class.


In the pagination concept, we learned about the various return type interfaces, such as the page interface and the slice interface, and we were able to differentiate between the two.


In addition, we go over the use cases for both the page interface and the slice interface in depth.


Keep learning and keep growing.

(getButton) #text=(Next: Spring Data JPA DTO Projections) #icon=(link) #color=(#2339bd)

Post a Comment

2 Comments
Post a Comment

#buttons=(Accept !) #days=(20)

Our website uses cookies to enhance your experience. Learn More
Accept !
To Top