What is Pagination?
Pagination is the process of dividing large data sets into smaller, manageable chunks, called pages. Instead of returning all rows from a database table (which can be thousands), you fetch a limited number of rows per request (like 10, 20, or 50).
Why Use Pagination?
- Performance: Reduces memory usage and improves response time.
- Scalability: Fetching 10 records is faster and lighter than fetching 10,000.
- User Experience: UI can show data page-by-page, making it readable.
Pagination Support in Spring Data JPA
Spring Data JPA provides built-in support for pagination using:
Pageable
interfacePage<T>
andSlice<T>
interfaces
Use Case: Pagination on a Product
Entity
We’ll create a Product
entity and implement an API to fetch products with pagination.
Repository
Spring Data JPA provides pagination-ready methods out of the box.
import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; public interface ProductRepository extends JpaRepository<Product, Long> { Page<Product> findAll(Pageable pageable); }
Service Layer
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.*; import org.springframework.stereotype.Service; @Service public class ProductService { @Autowired private ProductRepository productRepository; public Page<Product> getProducts(int page, int size, String sortBy) { Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy)); return productRepository.findAll(pageable); } }
Controller Example
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/products") public class ProductController { @Autowired private ProductService productService; @GetMapping public Page<Product> getAllProducts( @RequestParam(defaultValue = "0") int page, // Page number @RequestParam(defaultValue = "5") int size, // Page size @RequestParam(defaultValue = "id") String sortBy // Sort field ) { return productService.getProducts(page, size, sortBy); } }
Sample API Calls
URL: /api/products?page=0&size=10&sortBy=name
Returns:
{ "content": [ { "id": 1, "name": "Product 1", "price": 10.0 }, ... ], "totalPages": 10, "totalElements": 100, "last": false, "size": 10, "number": 0, "sort": {...}, "first": true, "numberOfElements": 10, "empty": false }
Understanding the Page<T>
Object
Spring’s Page<T>
object gives you:
getContent()
– list of current page contentgetTotalElements()
– total number of recordsgetTotalPages()
– total pagesgetNumber()
– current page numberisFirst()
/isLast()
– is it the first/last pagegetSize()
– size of each page
Pagination with Sorting
You can sort the result easily:
Pageable pageable = PageRequest.of(page, size, Sort.by("price").descending());
Or for multiple fields:
Sort sort = Sort.by("price").descending().and(Sort.by("name")); Pageable pageable = PageRequest.of(page, size, sort);
Slice<T>
in Spring Data JPA
Slice<T>
is similar to Page<T>
, but it doesn’t fetch the total number of elements or total pages.
When to use Slice<T>
instead of Page<T>
?
Use Slice<T>
when:
- You don’t care about the total number of items in the result.
- You just want to fetch the next chunk/page of data.
- You want better performance, especially with very large datasets, because
Page<T>
executes an additionalCOUNT(*)
query to get totals, whileSlice<T>
skips that.
Feature | Page<T> | Slice<T> |
---|---|---|
Total items | Yes (getTotalElements() ) | No |
Total pages | Yes (getTotalPages() ) | No |
Has next/prev page? | Yes | Yes (hasNext() , hasPrevious() ) |
Additional COUNT query? | Yes | No (faster) |
How Does Slice<T>
Work Internally?
To determine if more data is available, Slice<T>
fetches one extra record than requested. So if you request size=5
, it actually queries 6 records.
- If it finds 6 records → it sets
hasNext = true
and drops the extra record. - If less than or equal to 5 records → it sets
hasNext = false
.
This allows efficient pagination without counting total rows.