一次性從數據庫查出所有數據到內存 List,再在 Java 層按頁切片返回。適合數據量小、變化頻繁、需複雜排序/篩選的場景 (如後台管理幾百條配置數據)。
public class MemoryPager {
private final List data;
private final int pageSize;
private MemoryPager(List data, int pageSize) {
if (data == null || data.isEmpty()) throw new IllegalArgumentException("數據不能為空");
if (pageSize <= 0) throw new IllegalArgumentException("頁大小必須 > 0");
this.data = Collections.unmodifiableList(new ArrayList<>(data)); // 防禦性拷貝
this.pageSize = pageSize;
}
public static MemoryPager of(List data, int pageSize) {
return new MemoryPager<>(data, pageSize);
}
// 獲取指定頁 (1-based)
public List getPage(int pageNum) {
if (pageNum < 1) return Collections.emptyList();
int from = (pageNum - 1) * pageSize;
if (from >= data.size()) return Collections.emptyList();
int to = Math.min(from + pageSize, data.size());
return data.subList(from, to); // 視圖,無拷貝開銷
}
// 分頁元數據
public PageInfo getPageInfo(int pageNum) {
long total = data.size();
int totalPages = (int) ((total + pageSize - 1) / pageSize);
List content = getPage(pageNum);
return new PageInfo(pageNum, pageSize, total, totalPages, content);
}
// 靜態內部類:分頁信息
public static class PageInfo {
public final int pageNum, pageSize, totalPages;
public final long total;
public final List content;
public PageInfo(int pageNum, int pageSize, long total, int totalPages, List content) {
this.pageNum = pageNum; this.pageSize = pageSize; this.total = total;
this.totalPages = totalPages; this.content = content;
}
}
}
public class PagerDemo {
public static void main(String[] args) {
// 模擬數據庫查出 12 條數據
List allData = IntStream.rangeClosed(1, 12).boxed().collect(Collectors.toList());
MemoryPager pager = MemoryPager.of(allData, 5); // 每頁 5 條
System.out.println("第1頁: " + pager.getPage(1)); // [1,2,3,4,5]
System.out.println("第2頁: " + pager.getPage(2)); // [6,7,8,9,10]
System.out.println("第3頁: " + pager.getPage(3)); // [11,12]
System.out.println("第4頁: " + pager.getPage(4)); // []
// 獲取完整分頁信息
MemoryPager.PageInfo info = pager.getPageInfo(2);
System.out.printf("頁碼:%d 大小:%d 總數:%d 總頁:%d 數據:%s%n",
info.pageNum, info.pageSize, info.total, info.totalPages, info.content);
}
}
| 維度 | 假分頁 (內存) | 真分頁 (SQL LIMIT/OFFSET) |
|---|---|---|
| 數據量適用 | < 10,000 條 (視內存) | 無上限 |
| 首次加載 | 慢 (全量查詢+傳輸) | 快 (只查一頁) |
| 翻頁響應 | 極快 (內存切片) | 需再次查詢 |
| 排序/篩選 | Java 靈活實現 (Stream API) | SQL 複雜、受限 |
| 數據一致性 | 快照隔離 (加載瞬間) | 實時 (每頁查詢) |
| 內存佔用 | 高 (全量對象) | 低 (僅一頁) |