Database Pagination কী?
Pagination হলো বড় ডেটাসেটকে ছোট ছোট ভাগে ভাগ করে দেখানোর পদ্ধতি। একসাথে লক্ষ লক্ষ রেকর্ড লোড না করে Page ভিত্তিক করে ডেটা আনা হয়। এটি Performance ও User Experience উভয়ই উন্নত করে।
কেন Pagination দরকার?
-- ❌ খারাপ উদাহরণ: সব ডেটা একসাথে
SELECT * FROM products; -- ১০ লক্ষ রেকর্ড!
-- ✅ ভালো উদাহরণ: Page ভিত্তিক
SELECT * FROM products LIMIT 20 OFFSET 0; -- Page 1
SELECT * FROM products LIMIT 20 OFFSET 20; -- Page 2
SELECT * FROM products LIMIT 20 OFFSET 40; -- Page 3
সুবিধা:
- Memory কম ব্যবহার হয়
- Database Load কম
- Network Traffic কম
- User দ্রুত ফলাফল পায়
SQL Pagination পদ্ধতি
LIMIT/OFFSET (সাধারণ পদ্ধতি)
-- Page 1: প্রথম ২০টি রেকর্ড
SELECT id, name, price FROM products
ORDER BY id
LIMIT 20 OFFSET 0;
-- Page 2: পরের ২০টি রেকর্ড
SELECT id, name, price FROM products
ORDER BY id
LIMIT 20 OFFSET 20;
-- Page N: OFFSET = (page - 1) * pageSize
SELECT id, name, price FROM products
ORDER BY id
LIMIT 20 OFFSET 100; -- Page 6
Keyset/Cursor Pagination (আরও দক্ষ)
-- প্রথম Page
SELECT id, name, price FROM products
ORDER BY id
LIMIT 20;
-- শেষ id = 20
-- পরের Page (last_id = 20 ব্যবহার করে)
SELECT id, name, price FROM products
WHERE id > 20 -- Index ব্যবহার করে, OFFSET নয়
ORDER BY id
LIMIT 20;
Keyset Pagination কেন ভালো?
- OFFSET বড় হলে ধীর হয় (
OFFSET 100000= ১ লক্ষ Row skip করতে হয়) - Keyset Pagination সবসময় Index ব্যবহার করে — দ্রুত
Spring Boot JPA-তে Pagination
Repository
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface ProductRepository extends JpaRepository<Product, Long> {
// Built-in Pagination support
Page<Product> findAll(Pageable pageable);
// Filter সহ Pagination
Page<Product> findByCategory(String category, Pageable pageable);
// Price range সহ Pagination
Page<Product> findByPriceBetween(double minPrice, double maxPrice, Pageable pageable);
}
Service
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
// Basic Pagination
public Page<Product> getProducts(int page, int size) {
Pageable pageable = PageRequest.of(page, size);
return productRepository.findAll(pageable);
}
// Sorting সহ Pagination
public Page<Product> getProductsSorted(int page, int size, String sortBy) {
Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy).ascending());
return productRepository.findAll(pageable);
}
// Multi-field Sorting
public Page<Product> getProductsMultiSort(int page, int size) {
Sort sort = Sort.by(
Sort.Order.asc("category"),
Sort.Order.desc("price")
);
Pageable pageable = PageRequest.of(page, size, sort);
return productRepository.findAll(pageable);
}
// Category Filter সহ Pagination
public Page<Product> getByCategory(String category, int page, int size) {
Pageable pageable = PageRequest.of(page, size);
return productRepository.findByCategory(category, pageable);
}
}
Controller
@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping
public ResponseEntity<Map<String, Object>> getProducts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "id") String sortBy
) {
Page<Product> productPage = productService.getProductsSorted(page, size, sortBy);
Map<String, Object> response = new HashMap<>();
response.put("products", productPage.getContent());
response.put("currentPage", productPage.getNumber());
response.put("totalItems", productPage.getTotalElements());
response.put("totalPages", productPage.getTotalPages());
response.put("isFirst", productPage.isFirst());
response.put("isLast", productPage.isLast());
return ResponseEntity.ok(response);
}
}
Page Object-এর উপকারী মেথড
Page<Product> page = productRepository.findAll(pageable);
page.getContent(); // বর্তমান Page-এর ডেটা List
page.getNumber(); // বর্তমান Page নম্বর (0-based)
page.getSize(); // Page Size
page.getTotalElements(); // মোট রেকর্ড সংখ্যা
page.getTotalPages(); // মোট Page সংখ্যা
page.isFirst(); // প্রথম Page কিনা
page.isLast(); // শেষ Page কিনা
page.hasNext(); // পরের Page আছে কিনা
page.hasPrevious(); // আগের Page আছে কিনা
Custom Pagination Response DTO
public class PageResponse<T> {
private List<T> content;
private int currentPage;
private long totalItems;
private int totalPages;
private boolean isFirst;
private boolean isLast;
private boolean hasNext;
private boolean hasPrevious;
public static <T> PageResponse<T> of(Page<T> page) {
PageResponse<T> response = new PageResponse<>();
response.setContent(page.getContent());
response.setCurrentPage(page.getNumber());
response.setTotalItems(page.getTotalElements());
response.setTotalPages(page.getTotalPages());
response.setFirst(page.isFirst());
response.setLast(page.isLast());
response.setHasNext(page.hasNext());
response.setHasPrevious(page.hasPrevious());
return response;
}
}
Keyset Pagination in Spring JPA
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
// Cursor-based Pagination: last seen id-এর পরের records
@Query("SELECT p FROM Product p WHERE p.id > :lastId ORDER BY p.id ASC")
List<Product> findNextPage(@Param("lastId") Long lastId, Pageable pageable);
}
@Service
public class ProductService {
public List<Product> getNextPage(Long lastId, int size) {
Pageable pageable = PageRequest.of(0, size);
return productRepository.findNextPage(lastId, pageable);
}
}
সংক্ষেপে
| বিষয় | বিবরণ |
|---|---|
| Pagination | বড় ডেটা Page ভিত্তিক লোড করা |
| LIMIT/OFFSET | সহজ কিন্তু বড় OFFSET-এ ধীর |
| Keyset Pagination | সবসময় দ্রুত, Index ব্যবহার করে |
PageRequest.of() |
Spring-এ Pageable তৈরির পদ্ধতি |
Page<T> |
Pagination metadata সহ ডেটা রাখে |
Slice<T> |
Metadata কম, শুধু isLast/isNext জানে |
উপসংহার
Pagination যেকোনো Production অ্যাপ্লিকেশনে অপরিহার্য। Spring Data JPA-এর Pageable ইন্টারফেস ব্যবহার করে অত্যন্ত সহজে Pagination implement করা যায়। বড় টেবিলের জন্য Keyset Pagination ব্যবহার করুন — এটি OFFSET-based Pagination-এর চেয়ে অনেক দ্রুত।