Printing is unavailable

This course is licensed for personal online viewing only.

Public preview • CL-P000000-C41-L1738-D6CB623A

Home Dashboard
Chapter 359 · Module 4 — Spring Data JPA and Database Persistence

Pagination and Sorting with Spring Data JPA

Priority
  • JobHigh
  • InterviewMedium
  • DevelopmentHigh
5,097
words
29
min read
2
tools

1. Learning Outcomes#

इस chapter को पूरा करने के बाद आप:

  • समझ पाएँगे कि बड़े database results को एक साथ retrieve करना क्यों सही approach नहीं है।
  • Pageable का role और PageRequest का उपयोग समझ पाएँगे।
  • zero-based page number और page size को सही तरीके से handle कर पाएँगे।
  • findAll(Pageable) और custom repository methods में pagination apply कर पाएँगे।
  • Page<T>, Slice<T> और List<T> के बीच practical difference समझ पाएँगे।
  • Page<T> से total elements, total pages और navigation metadata पढ़ पाएँगे।
  • समझ पाएँगे कि Page<T> के लिए additional count query की आवश्यकता क्यों पड़ सकती है।
  • Sort का उपयोग करके ascending, descending और multiple-field sorting कर पाएँगे।
  • pagination और sorting को एक ही request में combine कर पाएँगे।
  • REST API में page, size और sort information safely accept कर पाएँगे।
  • client-supplied page size पर reasonable limit लगा पाएँगे।
  • large offset-based pagination की performance limitation पहचान पाएँगे।

2. सबसे पहले समस्या समझें#

मान लीजिए आपके products table में शुरुआत में केवल 100 records हैं।

ऐसी स्थिति में सभी products retrieve करना शायद problem न लगे।

लेकिन कुछ महीनों बाद उसी table में:

  • 10,000 products
  • 1,00,000 products
  • या 10,00,000 products

हो सकते हैं।

अगर application हर request पर सभी rows database से पढ़ने लगे, तो unnecessary work होगा।

Database को अधिक rows पढ़नी पड़ेंगी।

Network पर अधिक data जाएगा।

Spring Boot application को अधिक objects बनाने पड़ेंगे।

Memory usage बढ़ सकती है।

API response बड़ा और slow हो सकता है।

Frontend को भी हजारों records एक साथ process करने पड़ सकते हैं।

यही वह problem है जिसे pagination solve करती है।

Key Idea

Pagination का मतलब पूरे result को एक साथ देने के बजाय उसे छोटे-छोटे pages में बाँटना है।

उदाहरण के लिए, अगर 1,000 products हैं और हर page में 20 products चाहिए, तो client पहले केवल शुरुआती 20 products माँग सकता है।

फिर आवश्यकता होने पर अगला page माँगा जा सकता है।

3. Definition#

English Definition

Pagination is the process of dividing a large result set into smaller, manageable pages and retrieving only the required portion of data for a request.

सरल भाषा में, pagination का अर्थ है:

सारा data एक साथ मत लाओ। अभी जितना चाहिए, उतना ही लाओ।

Sorting का अर्थ है result को किसी property के अनुसार क्रम में arrange करना।

उदाहरण:

  • price low to high
  • price high to low
  • name A to Z
  • newest records first

Spring Data JPA इन दोनों needs को standard abstractions के माध्यम से support करता है:

  • Pageable
  • PageRequest
  • Page<T>
  • Slice<T>
  • Sort

4. Pagination का basic mental model#

एक API request को इस तरह सोचिए:

Visual Diagram80%

Rendering diagram…

यहाँ client यह नहीं कहता कि "मुझे पूरा table दो।"

Client कहता है:

"मुझे page 0 के 20 records दो और उन्हें price के अनुसार sort करो।"

Repository उस request को database query में apply करती है।

5. Pageable क्या है?#

Pageable Spring Data का pagination abstraction है।

यह स्वयं database data नहीं है।

यह केवल यह बताता है कि result का कौन-सा हिस्सा चाहिए।

एक Pageable object सामान्यतः यह information रखता है:

  • कौन-सा page चाहिए
  • एक page में कितने records चाहिए
  • sorting कैसे करनी है

उदाहरण की सोच:

page = 0

size = 20

इसका अर्थ है:

पहला page चाहिए और अधिकतम 20 records चाहिए।

Remember

Pageable request information represent करता है। Actual records repository query execute होने के बाद मिलते हैं।

6. PageRequest क्या है?#

Pageable एक interface है।

Pagination request बनाने के लिए सबसे commonly used implementation PageRequest है।

सबसे simple pagination request:

JAVA
Pageable pageable = PageRequest.of(0, 20);

यहाँ:

  • 0 = page number
  • 20 = page size

इसका अर्थ है:

पहले page के अधिकतम 20 records चाहिए।

Zero-based page number को ध्यान से समझें#

Spring Data pagination में page numbering सामान्यतः zero-based होती है।

इसलिए:

User-visible idea Spring page number
First page 0
Second page 1
Third page 2
Fourth page 3

यह beginner mistakes का बहुत common कारण है।

अगर frontend पर user "Page 1" देख रहा है, तो backend internally page=0 use कर सकता है।

Common Mistake

PageRequest.of(1, 20) को first page समझना गलत है। यह second page request करता है।

Page size क्या बताता है?#

Page size बताता है कि एक page में अधिकतम कितने elements माँगे जा रहे हैं।

JAVA
Pageable pageable = PageRequest.of(0, 10);

यह first page के अधिकतम 10 records माँगता है।

JAVA
Pageable pageable = PageRequest.of(0, 50);

यह first page के अधिकतम 50 records माँगता है।

बहुत बड़ा page size pagination के purpose को कमजोर कर सकता है।

अगर आपके पास 5,00,000 records हैं और client size=500000 भेजता है, तो technically pagination parameter मौजूद है, लेकिन practically application लगभग पूरा result retrieve कर रही है।

इसलिए REST APIs में page size पर limit लगाना important है।

7. Repository में findAll(Pageable) का उपयोग#

अगर repository JpaRepository extend करती है, तो आपको paginated findAll functionality पहले से मिलती है।

उदाहरण:

JAVA
public interface ProductRepository extends JpaRepository<Product, Long> {
}

अब service में pagination request बनाई जा सकती है:

JAVA
Pageable pageable = PageRequest.of(0, 20);

Page<Product> productPage =
        productRepository.findAll(pageable);

यहाँ important flow यह है:

  1. PageRequest.of(0, 20) pagination instructions बनाता है।
  2. findAll(pageable) repository को वे instructions देता है।
  3. Spring Data JPA required query execute करता है।
  4. requested records Page<Product> में वापस आते हैं।

सिर्फ records ही नहीं, pagination metadata भी मिलता है।

8. Page<T> को समझें#

Page<Product> को केवल List<Product> मत समझिए।

इसमें current page के records के साथ pagination-related metadata भी रहता है।

उदाहरण:

JAVA
Page<Product> page =
        productRepository.findAll(PageRequest.of(0, 20));

List<Product> products = page.getContent();

long totalElements = page.getTotalElements();

int totalPages = page.getTotalPages();

int currentPage = page.getNumber();

int pageSize = page.getSize();

int currentElementCount = page.getNumberOfElements();

boolean hasNext = page.hasNext();

boolean hasPrevious = page.hasPrevious();

अब एक-एक करके अर्थ समझते हैं।

getContent()#

JAVA
page.getContent();

Current page के actual records देता है।

अगर page size 20 है, तो सामान्यतः अधिकतम 20 objects मिलेंगे।

Last page पर इससे कम records हो सकते हैं।

getNumber()#

Current zero-based page number देता है।

अगर current page second page है, तो value 1 होगी।

getSize()#

Requested page size बताता है।

उदाहरण:

JAVA
PageRequest.of(2, 25);

तो page size 25 है।

getNumberOfElements()#

Current page पर वास्तव में कितने elements आए हैं, यह बताता है।

मान लीजिए total 53 records हैं और page size 20 है।

तब pages broadly इस तरह होंगे:

Page number Records on page
0 20
1 20
2 13

तीसरे page पर getNumberOfElements() 13 दे सकता है।

getTotalElements()#

पूरे filtered result में कुल कितने matching records हैं, यह बताता है।

अगर database में matching products 53 हैं:

JAVA
page.getTotalElements();

value 53 दे सकता है।

getTotalPages()#

पूरे result को requested page size में divide करने पर कितने pages बनेंगे, यह बताता है।

अगर:

  • total elements = 53
  • page size = 20

तो total pages = 3

होंगे।

9. Page<T> के पीछे count query क्यों आ सकती है?#

यह एक बहुत important concept है।

मान लीजिए application को केवल current 20 rows नहीं चाहिए।

Frontend को यह भी दिखाना है:

Page 1 of 250

और:

5000 results found

Current rows की query से Spring Data को automatically यह नहीं पता चलता कि पूरे filtered result में कुल कितनी rows हैं।

इसलिए total count जानने के लिए database को अक्सर दूसरी query execute करनी पड़ती है।

Conceptual flow:

Visual Diagram80%

Rendering diagram…

उदाहरण के लिए conceptual SQL कुछ इस तरह हो सकती है:

SQL
SELECT *
FROM products
ORDER BY id
LIMIT 20 OFFSET 0;

और total count के लिए अलग query:

SQL
SELECT COUNT(*)
FROM products;

Actual SQL database, query और JPA provider के अनुसार अलग हो सकती है।

Key Idea

Page<T> convenient है क्योंकि यह total metadata देता है, लेकिन total जानने के लिए additional database work की आवश्यकता पड़ सकती है।

Spring Data कुछ situations में unnecessary count query avoid कर सकता है, लेकिन developer को यह assume नहीं करना चाहिए कि Page<T> हमेशा केवल एक query execute करेगा।

10. Custom repository method में Pageable#

Pagination केवल findAll() तक सीमित नहीं है।

Derived query method के साथ भी Pageable use किया जा सकता है।

मान लीजिए products को category के अनुसार retrieve करना है:

JAVA
public interface ProductRepository extends JpaRepository<Product, Long> {

    Page<Product> findByCategory(
            String category,
            Pageable pageable
    );
}

Service:

JAVA
public Page<Product> getProductsByCategory(
        String category,
        int page,
        int size
) {
    Pageable pageable = PageRequest.of(page, size);

    return productRepository.findByCategory(
            category,
            pageable
    );
}

यहाँ category filter और pagination दोनों apply होते हैं।

यह महत्वपूर्ण है क्योंकि pagination filtering के बाद matching result पर apply होती है।

11. @Query method के साथ pagination#

Custom JPQL query के साथ भी Pageable use किया जा सकता है।

JAVA
@Query("select p from Product p where p.active = true")
Page<Product> findActiveProducts(Pageable pageable);

जब return type Page<Product> है, Spring Data को total matching records जानने के लिए count query की आवश्यकता हो सकती है।

Complex query में explicit count query देना useful हो सकता है:

JAVA
@Query(
    value = "select p from Product p where p.active = true",
    countQuery = "select count(p) from Product p where p.active = true"
)
Page<Product> findActiveProducts(Pageable pageable);

यहाँ:

  • value current page का data retrieve करने वाली query है।
  • countQuery total matching records calculate करती है।

Simple queries के लिए Spring Data count query derive कर सकता है।

Complex queries में developer को generated query और performance समझनी चाहिए।

12. अगर total count चाहिए ही नहीं तो?#

यहीं Slice<T> useful होता है।

मान लीजिए mobile app infinite scrolling use करती है।

User नीचे scroll करता है और application अगला batch load करती है।

ऐसी screen को शायद यह जानने की आवश्यकता नहीं है कि:

Total records = 2,43,581

उसे केवल यह जानना है:

क्या अगला batch मौजूद है?

ऐसे case में Slice<T> useful हो सकता है।

13. Slice<T> क्या है?#

Slice<T> current chunk of data और navigation information देता है, लेकिन complete total count provide नहीं करता।

Repository example:

JAVA
public interface ProductRepository extends JpaRepository<Product, Long> {

    Slice<Product> findByCategory(
            String category,
            Pageable pageable
    );
}

Usage:

JAVA
Pageable pageable = PageRequest.of(0, 20);

Slice<Product> slice =
        productRepository.findByCategory(
                "Laptop",
                pageable
        );

Useful methods:

JAVA
List<Product> products = slice.getContent();

boolean hasNext = slice.hasNext();

boolean hasPrevious = slice.hasPrevious();

int currentPage = slice.getNumber();

int pageSize = slice.getSize();

लेकिन:

JAVA
slice.getTotalElements();

जैसी total-count functionality Slice का उद्देश्य नहीं है।

Slice कैसे decide करता है कि next page है?#

Conceptually Spring Data को यह जानना होता है कि requested chunk के बाद और data मौजूद है या नहीं।

इसी जानकारी के आधार पर hasNext() दिया जा सकता है।

लेकिन उसे पूरे result का exact total calculate करने की आवश्यकता नहीं होती।

इसलिए large result sets में, जहाँ total count business requirement नहीं है, Slice useful choice हो सकता है।

14. Page, Slice और List की तुलना#

Return type Current records Total elements Total pages Has next information Typical use
Page<T> Yes Yes Yes Yes Numbered pagination UI
Slice<T> Yes No full total No full total Yes Infinite scroll / load more
List<T> Yes No No No pagination metadata Only records are needed

यह difference interview और real development दोनों में important है।

List<T> के साथ Pageable#

Custom repository method Pageable accept करके List<T> भी return कर सकता है।

उदाहरण:

JAVA
List<Product> findByCategory(
        String category,
        Pageable pageable
);

इससे query requested page/limit के अनुसार constrained हो सकती है।

लेकिन return value में:

  • total pages
  • total elements
  • hasNext()

जैसा metadata नहीं मिलेगा।

इसलिए return type business requirement के अनुसार चुनना चाहिए।

Remember

हर pagination use case के लिए Page<T> automatically best choice नहीं है।

15. Sorting को समझें#

Pagination यह तय करती है कि result का कौन-सा हिस्सा retrieve करना है।

Sorting यह तय करती है कि rows किस order में आएँगी।

Spring Data इसके लिए Sort abstraction देता है।

16. Simple ascending sorting#

मान लीजिए products को name के अनुसार A to Z sort करना है।

JAVA
Sort sort = Sort.by("name").ascending();

List<Product> products =
        productRepository.findAll(sort);

यहाँ "name" entity property का नाम है।

Database column का physical name अलग हो सकता है।

Spring Data repository sorting सामान्यतः entity property के आधार पर define की जाती है।

17. Descending sorting#

Latest or highest value पहले चाहिए तो descending sorting use की जा सकती है।

JAVA
Sort sort = Sort.by("price").descending();

List<Product> products =
        productRepository.findAll(sort);

यह highest price से lower price की ओर result order करेगा।

18. Sort.Direction का उपयोग#

Direction programmatically decide करनी हो तो:

JAVA
Sort.Direction direction = Sort.Direction.DESC;

Sort sort = Sort.by(direction, "price");

यह REST API parameters के साथ useful है।

19. Multiple properties से sorting#

कई बार एक property पर्याप्त नहीं होती।

मान लीजिए:

  1. पहले category ascending
  2. same category में price descending

चाहिए।

JAVA
Sort sort = Sort.by(
        Sort.Order.asc("category"),
        Sort.Order.desc("price")
);

इसका मतलब:

पहला sorting level category है।

अगर कई rows की category same है, तो उनके बीच price descending order decide करेगा।

दूसरा तरीका:

JAVA
Sort sort = Sort.by("category")
        .ascending()
        .and(
            Sort.by("price").descending()
        );

दोनों approaches का goal समान है।

20. Pagination और sorting को combine करना#

Real applications में यही सबसे common pattern है।

उदाहरण:

  • page = 0
  • size = 20
  • sort by price
  • descending order
JAVA
Sort sort = Sort.by("price").descending();

Pageable pageable =
        PageRequest.of(0, 20, sort);

Page<Product> result =
        productRepository.findAll(pageable);

अब query केवल first 20 records retrieve करेगी, लेकिन record selection sorting order के बाद meaningful होगा।

Conceptual flow:

Visual Diagram80%

Rendering diagram…

Important

Pagination के साथ stable sorting बहुत useful है। बिना predictable order के pages के बीच records का क्रम समझना मुश्किल हो सकता है।

21. REST API में page, size और sort accept करना#

अब इसे practical API में use करते हैं।

मान लीजिए endpoint है:

GET /api/products

Client यह request भेज सकता है:

/api/products?page=0&size=20&sortBy=price&direction=desc

Beginner-friendly explicit controller:

JAVA
@RestController
@RequestMapping("/api/products")
public class ProductController {

    private final ProductRepository productRepository;

    public ProductController(
            ProductRepository productRepository
    ) {
        this.productRepository = productRepository;
    }

    @GetMapping
    public Page<Product> getProducts(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size,
            @RequestParam(defaultValue = "id") String sortBy,
            @RequestParam(defaultValue = "asc") String direction
    ) {
        Sort.Direction sortDirection =
                direction.equalsIgnoreCase("desc")
                        ? Sort.Direction.DESC
                        : Sort.Direction.ASC;

        Sort sort =
                Sort.by(sortDirection, sortBy);

        Pageable pageable =
                PageRequest.of(page, size, sort);

        return productRepository.findAll(pageable);
    }
}

Flow समझिए।

Client pagination information भेजता है।

Controller उससे Sort बनाता है।

फिर Sort को PageRequest में देता है।

Repository उस pagination request के अनुसार data retrieve करती है।

22. लेकिन client input पर blind trust नहीं करना चाहिए#

ऊपर का example concept समझाने के लिए simple है।

Production API में कुछ validation जरूरी है।

Client भेज सकता है:

page=-10

या:

size=1000000

या invalid sorting property भेज सकता है।

इन values को directly use करना reliable API design नहीं है।

23. Page size पर reasonable limit लगाएँ#

मान लीजिए API policy है:

  • minimum size = 1
  • default size = 20
  • maximum size = 100

एक simple approach:

JAVA
int safePage = Math.max(page, 0);

int safeSize = Math.min(
        Math.max(size, 1),
        100
);

अब:

  • negative page 0 में normalize होगा।
  • size 0 या negative हो तो minimum 1 होगा।
  • size 100 से बड़ा हो तो maximum 100 होगा।

फिर:

JAVA
Pageable pageable =
        PageRequest.of(
                safePage,
                safeSize,
                sort
        );
Key Idea

Pagination parameters user input हैं। इसलिए उन्हें validation और business limits के साथ handle करना चाहिए।

24. Sort property को भी validate करें#

Client यदि arbitrary string भेजता है:

sortBy=whatever

तो entity में वह property मौजूद न होने पर request fail हो सकती है।

Production API में allowed sort fields whitelist करना better है।

JAVA
private static final Set<String> ALLOWED_SORT_FIELDS =
        Set.of(
                "id",
                "name",
                "price",
                "createdAt"
        );

फिर:

JAVA
String safeSortBy =
        ALLOWED_SORT_FIELDS.contains(sortBy)
                ? sortBy
                : "id";

और:

JAVA
Sort sort =
        Sort.by(sortDirection, safeSortBy);

इससे API केवल supported sorting fields allow करती है।

25. एक cleaner service example#

Controller का काम request लेना है।

Business-related pagination rules service में रखना अक्सर cleaner design देता है।

JAVA
@Service
public class ProductService {

    private static final int MAX_PAGE_SIZE = 100;

    private static final Set<String> ALLOWED_SORT_FIELDS =
            Set.of(
                    "id",
                    "name",
                    "price",
                    "createdAt"
            );

    private final ProductRepository productRepository;

    public ProductService(
            ProductRepository productRepository
    ) {
        this.productRepository = productRepository;
    }

    public Page<Product> getProducts(
            int page,
            int size,
            String sortBy,
            String direction
    ) {
        int safePage = Math.max(page, 0);

        int safeSize = Math.min(
                Math.max(size, 1),
                MAX_PAGE_SIZE
        );

        String safeSortBy =
                ALLOWED_SORT_FIELDS.contains(sortBy)
                        ? sortBy
                        : "id";

        Sort.Direction sortDirection =
                direction.equalsIgnoreCase("desc")
                        ? Sort.Direction.DESC
                        : Sort.Direction.ASC;

        Sort sort =
                Sort.by(
                        sortDirection,
                        safeSortBy
                );

        Pageable pageable =
                PageRequest.of(
                        safePage,
                        safeSize,
                        sort
                );

        return productRepository.findAll(pageable);
    }
}

यह example कई important ideas combine करता है:

  • page validation
  • page-size limit
  • safe sort field
  • sort direction
  • PageRequest
  • repository pagination

26. पूरा table retrieve करना क्यों avoid करना चाहिए?#

यह code technically valid हो सकता है:

JAVA
List<Product> products =
        productRepository.findAll();

लेकिन अगर table बहुत बड़ा है और API को केवल 20 records दिखाने हैं, तो यह poor choice हो सकती है।

Problem यह है कि application:

  1. सभी rows retrieve करती है।
  2. सभी entities memory में बनाती है।
  3. फिर शायद application level पर केवल कुछ records उपयोग करती है।

यह database pagination का benefit खत्म कर देता है।

ऐसा approach avoid करें:

JAVA
List<Product> allProducts =
        productRepository.findAll();

List<Product> firstTwenty =
        allProducts.stream()
                .limit(20)
                .toList();

क्यों?

क्योंकि .limit(20) Java में बाद में apply हो रहा है।

Database से data पहले ही application तक आ चुका है।

Better:

JAVA
Pageable pageable =
        PageRequest.of(0, 20);

Page<Product> page =
        productRepository.findAll(pageable);

अब database-level query requested range तक constrained हो सकती है।

27. Offset-based pagination कैसे काम करती है?#

Traditional page-number pagination database level पर अक्सर offset-style behavior produce करती है।

Conceptually:

page 0, size 20

तो:

SQL
SELECT *
FROM products
ORDER BY id
LIMIT 20 OFFSET 0;

page 1, size 20

तो conceptual offset 20 होगा।

page 10, size 20

तो conceptual offset 200 होगा।

एक simple formula है:

offset = page number × page size

इसलिए:

Page Size Conceptual offset
0 20 0
1 20 20
5 20 100
100 20 2000

28. Large offset की performance limitation#

अब एक important production concern आता है।

मान लीजिए:

  • page number = 50,000
  • size = 20

Conceptual offset होगा:

1,000,000

Query broadly ऐसी हो सकती है:

SQL
SELECT *
FROM products
ORDER BY id
LIMIT 20 OFFSET 1000000;

Database को केवल final 20 rows return करनी हैं।

लेकिन बहुत बड़े offset तक पहुँचने के लिए database engine को बड़ी संख्या में earlier rows process या skip करनी पड़ सकती हैं।

इसलिए deep pages increasingly expensive हो सकती हैं।

Warning

Pagination memory और response-size problems solve करती है, लेकिन extremely large offset अपने आप efficient नहीं बन जाता।

यह जानना important है:

page-number pagination useful है, लेकिन unlimited deep navigation के लिए हर situation में ideal नहीं है।

बहुत बड़े datasets और deep sequential navigation के लिए cursor/keyset-style approaches उपयोगी हो सकती हैं, लेकिन यहाँ मुख्य बात केवल limitation पहचानना है।

29. Page बनाम Slice performance decision#

अब practical decision लें।

Situation 1: Traditional admin table#

UI दिखाती है:

Page 3 of 42

और:

823 total products

यहाँ total count चाहिए।

Page<Product> suitable है।

Situation 2: Infinite scroll#

UI केवल:

Load more

करती है।

User को total pages नहीं दिखाने।

यहाँ Slice<Product> useful हो सकता है।

Situation 3: Limited internal processing#

आपको केवल requested records चाहिए।

कोई metadata नहीं चाहिए।

List<Product> with Pageable sufficient हो सकता है।

यह selection requirement-driven होना चाहिए।

30. एक practical repository design#

JAVA
public interface ProductRepository
        extends JpaRepository<Product, Long> {

    Page<Product> findByCategory(
            String category,
            Pageable pageable
    );

    Slice<Product> findByActiveTrue(
            Pageable pageable
    );

    List<Product> findByBrand(
            String brand,
            Pageable pageable
    );
}

अब तीन return types अलग needs represent करते हैं।

Page<Product>:

पूर्ण pagination metadata चाहिए।

Slice<Product>:

next chunk available है या नहीं, यह जानना है।

List<Product>:

केवल records चाहिए।

31. Stable sorting क्यों महत्वपूर्ण है?#

मान लीजिए आप केवल:

JAVA
PageRequest.of(0, 20);

use करते हैं।

अगर explicit sorting नहीं है, तो application को business-level predictable ordering assume नहीं करनी चाहिए।

Pagination APIs में stable deterministic ordering useful है।

उदाहरण:

JAVA
Sort sort = Sort.by(
        Sort.Order.desc("createdAt"),
        Sort.Order.desc("id")
);

यहाँ createdAt same होने पर id secondary ordering दे सकता है।

इससे page navigation अधिक predictable हो सकती है।

32. Common Mistakes#

1. First page के लिए 1 भेजना#

गलत assumption:

JAVA
PageRequest.of(1, 20);

first page है।

Spring Data में यह second page है।

First page:

JAVA
PageRequest.of(0, 20);

2. Client को unlimited page size देना#

Request:

size=500000

accept करना application और database पर unnecessary load डाल सकता है।

Maximum limit रखें।

3. Pagination करने से पहले पूरा table load करना#

यह:

JAVA
productRepository.findAll();

करके Java में list काटना database pagination नहीं है।

4. Page use करना जबकि total count की जरूरत नहीं#

अगर application केवल next batch जानना चाहती है, तो Slice अधिक suitable हो सकता है।

5. Slice से total pages की expectation रखना#

Slice full result total calculate करने के लिए designed नहीं है।

6. Arbitrary sort field accept करना#

Client-provided sort property validate करें।

7. Very large offset को free operation समझना#

Deep pages database के लिए costly हो सकती हैं।

8. Sorting के बिना predictable page order assume करना#

जहाँ consistent ordering business requirement है, explicit stable sort दें।

33. Quick Decision Guide#

Requirement Better starting choice
Content + total pages + total rows Page<T>
Content + whether next chunk exists Slice<T>
Only limited records List<T> with Pageable
Sort entire manageable result Sort
Paginate and sort PageRequest.of(page, size, sort)
Infinite scrolling Often Slice<T>
Traditional numbered pages Often Page<T>

34. Self Check#

अगर first page चाहिए और page size 25 है, तो कौन-सा request सही है?Show Answer
JAVA
PageRequest.of(0, 25);

क्योंकि Spring Data page numbering zero-based है।


Page<T> और Slice<T> में सबसे important practical difference क्या है?Show Answer

Page<T> total elements और total pages जैसी complete pagination metadata provide कर सकता है, जिसके लिए count query की आवश्यकता पड़ सकती है।

Slice<T> मुख्यतः current content और next slice मौजूद है या नहीं जैसी navigation information देता है। उसे complete total count की आवश्यकता नहीं होती।


क्या findAll() से सभी records लाकर Java में केवल 20 records रखना database pagination माना जाएगा?Show Answer

नहीं।

उस approach में पूरा result database से application तक आ चुका होता है। Proper pagination में database query को ही requested range तक limit किया जाता है।

35. Interview Preparation#

What is the difference between Page, Slice, and List in Spring Data pagination?Show Answer

Page<T> contains the current content along with total-element and total-page metadata. Slice<T> contains the current content and navigation information such as whether a next slice exists, without requiring the complete total count. A List<T> provides only the returned records and does not expose pagination metadata.

Key Points:

  • Page is useful for numbered pagination.
  • Slice is useful when total count is unnecessary.
  • List is suitable when only limited records are required.

Why interviewer asks this:

यह check किया जाता है कि candidate केवल PageRequest syntax नहीं, बल्कि pagination return-type trade-offs भी समझता है।


Why can Page<T> require an additional count query?Show Answer

A Page<T> may need the total number of matching rows to calculate metadata such as total elements and total pages. The data query returns the current page content, while an additional count query may be required to determine the complete result count.

Key Points:

  • Content query retrieves current rows.
  • Count query determines total matching rows.
  • Count queries can add database cost.

Why interviewer asks this:

यह pagination के database-level performance impact की understanding check करता है।


How do you combine pagination and sorting in Spring Data JPA?Show Answer

Create a Sort instance and pass it to PageRequest.of(page, size, sort). Then pass the resulting Pageable object to a repository method such as findAll(Pageable) or a custom method that accepts Pageable.

Key Points:

  • Build Sort.
  • Build PageRequest.
  • Pass Pageable to repository.
  • Validate client-controlled pagination and sorting parameters.

Why interviewer asks this:

यह practical REST API implementation knowledge check करता है।


What is a limitation of large offset-based pagination?Show Answer

With very large offsets, the database may need to process or skip a large number of preceding rows before returning the requested page. Therefore, deep pages can become increasingly expensive even when only a small number of rows are returned.

Key Points:

  • Small response size does not guarantee cheap query execution.
  • Deep offsets can reduce performance.
  • Alternative pagination strategies may be considered for very large datasets.

Why interviewer asks this:

यह check करता है कि candidate pagination को केवल API feature नहीं, बल्कि database performance concern के रूप में भी समझता है।

36. Recap#

इस chapter से मुख्य बातें:

  • Pagination बड़े results को छोटे pages में divide करती है।
  • Pageable pagination request describe करता है।
  • PageRequest Pageable बनाने का common तरीका है।
  • page numbering zero-based होती है।
  • findAll(Pageable) repository-level pagination देता है।
  • Page<T> content के साथ total metadata देता है।
  • total metadata के कारण count query की आवश्यकता पड़ सकती है।
  • Slice<T> total count के बिना next-chunk navigation के लिए useful है।
  • List<T> केवल records देता है।
  • Sort ascending, descending और multi-property sorting support करता है।
  • PageRequest में sorting combine की जा सकती है।
  • REST APIs को page, size और sort parameters validate करने चाहिए।
  • page size पर maximum limit रखना चाहिए।
  • बड़े tables को बिना आवश्यकता पूरा retrieve नहीं करना चाहिए।
  • बहुत बड़े offsets performance problem बन सकते हैं।
Interactive learning

Practice lab

Apply this chapter with guided activities, immediate feedback, explanations, and retry.

Practice loads when this section enters view.