An endpoint that returns every row works fine with ten records and falls over at
ten million. Spring Data bakes in pagination and sorting so you can return
bounded, ordered slices without hand-writing LIMIT and OFFSET.
Accept a Pageable
Add a Pageable parameter to a repository method and Spring returns a Page
that includes the content plus total counts.
public interface ProductRepository extends JpaRepository<Product, Long> {
Page<Product> findByCategory(String category, Pageable pageable);
}Wire it through the controller
Spring MVC resolves Pageable straight from query parameters like
?page=0&size=20&sort=price,desc, so the controller stays clean.
@GetMapping("/api/products")
public Page<ProductResponse> list(
@RequestParam String category,
Pageable pageable) {
return repository.findByCategory(category, pageable)
.map(ProductResponse::from);
}Beware deep offset paging
OFFSET 100000 still scans and discards those rows. For large datasets, prefer
keyset (cursor) pagination that seeks on an indexed column.
@Query("SELECT p FROM Product p WHERE p.id > :after ORDER BY p.id")
List<Product> findAfter(@Param("after") Long after, Pageable limit);Takeaways
- Never return unbounded collections from an API.
Pageablebinds directly frompage,size, andsortquery params.- Switch to keyset pagination when offsets get large.
Cap the maximum page size server-side so a client can't request a million rows in one call.