0
# Pagination
1
2
MyBatis-Plus provides comprehensive pagination support with automatic count queries, flexible page configuration, and seamless integration with query wrappers for efficient large dataset handling.
3
4
## Capabilities
5
6
### IPage Interface
7
8
Core pagination interface defining page structure and navigation methods.
9
10
```java { .api }
11
/**
12
* Pagination interface
13
* @param <T> Record type
14
*/
15
public interface IPage<T> extends Serializable {
16
17
/**
18
* Get current page records
19
*/
20
List<T> getRecords();
21
22
/**
23
* Set current page records
24
*/
25
IPage<T> setRecords(List<T> records);
26
27
/**
28
* Get total record count
29
*/
30
long getTotal();
31
32
/**
33
* Set total record count
34
*/
35
IPage<T> setTotal(long total);
36
37
/**
38
* Get page size
39
*/
40
long getSize();
41
42
/**
43
* Set page size
44
*/
45
IPage<T> setSize(long size);
46
47
/**
48
* Get current page number (1-based)
49
*/
50
long getCurrent();
51
52
/**
53
* Set current page number
54
*/
55
IPage<T> setCurrent(long current);
56
57
/**
58
* Get total page count
59
*/
60
default long getPages() {
61
if (getSize() == 0) {
62
return 0L;
63
}
64
long pages = getTotal() / getSize();
65
if (getTotal() % getSize() != 0) {
66
pages++;
67
}
68
return pages;
69
}
70
71
/**
72
* Check if has next page
73
*/
74
default boolean hasNext() {
75
return getCurrent() < getPages();
76
}
77
78
/**
79
* Check if has previous page
80
*/
81
default boolean hasPrevious() {
82
return getCurrent() > 1;
83
}
84
85
/**
86
* Get orders for sorting
87
*/
88
default List<OrderItem> orders() {
89
return new ArrayList<>();
90
}
91
92
/**
93
* Whether to optimize count query
94
*/
95
default boolean optimizeCountSql() {
96
return true;
97
}
98
99
/**
100
* Whether to search count (perform count query)
101
*/
102
default boolean searchCount() {
103
return true;
104
}
105
106
/**
107
* Get count ID for optimization
108
*/
109
default String countId() {
110
return null;
111
}
112
113
/**
114
* Get max limit for single query
115
*/
116
default Long maxLimit() {
117
return null;
118
}
119
}
120
```
121
122
### Page Class
123
124
Default pagination implementation with builder support and order configuration.
125
126
```java { .api }
127
/**
128
* Default pagination implementation
129
* @param <T> Record type
130
*/
131
public class Page<T> implements IPage<T> {
132
133
/**
134
* Default constructor
135
*/
136
public Page();
137
138
/**
139
* Constructor with current page and page size
140
* @param current Current page number (1-based)
141
* @param size Page size
142
*/
143
public Page(long current, long size);
144
145
/**
146
* Constructor with current page, page size, and total
147
* @param current Current page number
148
* @param size Page size
149
* @param total Total record count
150
*/
151
public Page(long current, long size, long total);
152
153
/**
154
* Constructor with search count control
155
* @param current Current page number
156
* @param size Page size
157
* @param searchCount Whether to perform count query
158
*/
159
public Page(long current, long size, boolean searchCount);
160
161
/**
162
* Constructor with all parameters
163
* @param current Current page number
164
* @param size Page size
165
* @param total Total record count
166
* @param searchCount Whether to perform count query
167
*/
168
public Page(long current, long size, long total, boolean searchCount);
169
170
/**
171
* Add order item for sorting
172
* @param orderItem Order configuration
173
*/
174
public Page<T> addOrder(OrderItem orderItem);
175
176
/**
177
* Add multiple order items
178
* @param orderItems Order configurations
179
*/
180
public Page<T> addOrder(List<OrderItem> orderItems);
181
182
/**
183
* Set orders (replaces existing)
184
* @param orders New order configurations
185
*/
186
public Page<T> setOrders(List<OrderItem> orders);
187
188
/**
189
* Set whether to optimize count SQL
190
* @param optimizeCountSql Optimization flag
191
*/
192
public Page<T> setOptimizeCountSql(boolean optimizeCountSql);
193
194
/**
195
* Set whether to search count
196
* @param searchCount Search count flag
197
*/
198
public Page<T> setSearchCount(boolean searchCount);
199
200
/**
201
* Set count ID for optimization
202
* @param countId Count ID
203
*/
204
public Page<T> setCountId(String countId);
205
206
/**
207
* Set max limit for single query
208
* @param maxLimit Max limit
209
*/
210
public Page<T> setMaxLimit(Long maxLimit);
211
}
212
```
213
214
### OrderItem Class
215
216
Sorting configuration for pagination queries.
217
218
```java { .api }
219
/**
220
* Order item for sorting configuration
221
*/
222
public class OrderItem implements Serializable {
223
224
/**
225
* Column name for sorting
226
*/
227
private String column;
228
229
/**
230
* Whether ascending (true) or descending (false)
231
*/
232
private boolean asc = true;
233
234
/**
235
* Constructor
236
*/
237
public OrderItem();
238
239
/**
240
* Constructor with column and direction
241
* @param column Column name
242
* @param asc Sort direction (true for ASC, false for DESC)
243
*/
244
public OrderItem(String column, boolean asc);
245
246
/**
247
* Static factory method for ascending order
248
* @param column Column name
249
* @return OrderItem for ascending sort
250
*/
251
public static OrderItem asc(String column);
252
253
/**
254
* Static factory method for descending order
255
* @param column Column name
256
* @return OrderItem for descending sort
257
*/
258
public static OrderItem desc(String column);
259
260
/**
261
* Static factory method for multiple ascending orders
262
* @param columns Column names
263
* @return List of OrderItems for ascending sorts
264
*/
265
public static List<OrderItem> ascs(String... columns);
266
267
/**
268
* Static factory method for multiple descending orders
269
* @param columns Column names
270
* @return List of OrderItems for descending sorts
271
*/
272
public static List<OrderItem> descs(String... columns);
273
274
// getters and setters...
275
}
276
```
277
278
## Usage Examples
279
280
**Basic Pagination:**
281
282
```java
283
// Simple pagination
284
Page<User> page = new Page<>(1, 10); // Page 1, 10 records per page
285
IPage<User> result = userService.page(page);
286
287
System.out.println("Total records: " + result.getTotal());
288
System.out.println("Total pages: " + result.getPages());
289
System.out.println("Current page: " + result.getCurrent());
290
System.out.println("Page size: " + result.getSize());
291
System.out.println("Records: " + result.getRecords().size());
292
System.out.println("Has next: " + result.hasNext());
293
System.out.println("Has previous: " + result.hasPrevious());
294
```
295
296
**Pagination with Query Conditions:**
297
298
```java
299
// Pagination with conditions
300
Page<User> page = new Page<>(1, 10);
301
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
302
wrapper.eq(User::getStatus, 1)
303
.like(User::getName, "John")
304
.orderByDesc(User::getCreateTime);
305
306
IPage<User> result = userService.page(page, wrapper);
307
308
// Or using mapper directly
309
IPage<User> result = userMapper.selectPage(page, wrapper);
310
```
311
312
**Pagination with Sorting:**
313
314
```java
315
// Using OrderItem for sorting
316
Page<User> page = new Page<>(1, 10);
317
page.addOrder(OrderItem.desc("create_time"))
318
.addOrder(OrderItem.asc("name"));
319
320
IPage<User> result = userService.page(page);
321
322
// Multiple orders at once
323
List<OrderItem> orders = Arrays.asList(
324
OrderItem.desc("create_time"),
325
OrderItem.asc("name"),
326
OrderItem.desc("id")
327
);
328
page.setOrders(orders);
329
330
// Factory methods for convenience
331
page.addOrder(OrderItem.descs("create_time", "update_time"))
332
.addOrder(OrderItem.ascs("name", "email"));
333
```
334
335
**Performance Optimization:**
336
337
```java
338
// Disable count query for better performance (when total not needed)
339
Page<User> page = new Page<>(1, 10, false); // searchCount = false
340
IPage<User> result = userService.page(page);
341
// result.getTotal() will be 0, but records are fetched normally
342
343
// Optimize count SQL
344
Page<User> page = new Page<>(1, 10);
345
page.setOptimizeCountSql(true); // Default is true
346
IPage<User> result = userService.page(page);
347
348
// Set count ID for complex queries
349
page.setCountId("customCountQuery");
350
351
// Set max limit to prevent large queries
352
page.setMaxLimit(1000L);
353
```
354
355
**Custom Pagination Queries:**
356
357
```java
358
// Custom mapper method with pagination
359
@Mapper
360
public interface UserMapper extends BaseMapper<User> {
361
362
@Select("SELECT u.*, d.name as dept_name FROM user u LEFT JOIN department d ON u.dept_id = d.id WHERE u.status = #{status}")
363
IPage<UserWithDept> selectUsersWithDept(IPage<UserWithDept> page, @Param("status") Integer status);
364
365
// XML-based custom query
366
IPage<User> selectActiveUsers(IPage<User> page, @Param("minAge") Integer minAge);
367
}
368
369
// Usage
370
Page<UserWithDept> page = new Page<>(1, 10);
371
IPage<UserWithDept> result = userMapper.selectUsersWithDept(page, 1);
372
373
Page<User> page = new Page<>(1, 10);
374
IPage<User> result = userMapper.selectActiveUsers(page, 18);
375
```
376
377
**Map-based Pagination:**
378
379
```java
380
// Paginate maps instead of entities
381
Page<Map<String, Object>> page = new Page<>(1, 10);
382
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
383
wrapper.select(User::getId, User::getName, User::getEmail)
384
.eq(User::getStatus, 1);
385
386
IPage<Map<String, Object>> result = userService.pageMaps(page, wrapper);
387
388
// Or using mapper
389
IPage<Map<String, Object>> result = userMapper.selectMapsPage(page, wrapper);
390
```
391
392
**Service Layer Chain Pagination:**
393
394
```java
395
// Using service chain methods
396
Page<User> page = new Page<>(1, 10);
397
IPage<User> result = userService.lambdaQuery()
398
.eq(User::getStatus, 1)
399
.gt(User::getAge, 18)
400
.orderByDesc(User::getCreateTime)
401
.page(page);
402
```
403
404
**Pagination Helper Utilities:**
405
406
```java
407
// Utility class for common pagination operations
408
public class PageUtils {
409
410
public static <T> Page<T> buildPage(int current, int size) {
411
return new Page<>(current, size);
412
}
413
414
public static <T> Page<T> buildPageWithOrder(int current, int size, String orderBy, boolean asc) {
415
Page<T> page = new Page<>(current, size);
416
page.addOrder(new OrderItem(orderBy, asc));
417
return page;
418
}
419
420
public static <T> PageResult<T> toPageResult(IPage<T> page) {
421
PageResult<T> result = new PageResult<>();
422
result.setRecords(page.getRecords());
423
result.setTotal(page.getTotal());
424
result.setCurrent(page.getCurrent());
425
result.setSize(page.getSize());
426
result.setPages(page.getPages());
427
return result;
428
}
429
}
430
431
// Usage
432
Page<User> page = PageUtils.buildPageWithOrder(1, 10, "create_time", false);
433
IPage<User> result = userService.page(page);
434
PageResult<User> pageResult = PageUtils.toPageResult(result);
435
```
436
437
**Error Handling and Validation:**
438
439
```java
440
// Validate pagination parameters
441
public IPage<User> getUsers(int current, int size) {
442
// Validate parameters
443
if (current < 1) {
444
throw new IllegalArgumentException("Page number must be positive");
445
}
446
if (size < 1 || size > 100) {
447
throw new IllegalArgumentException("Page size must be between 1 and 100");
448
}
449
450
Page<User> page = new Page<>(current, size);
451
return userService.page(page);
452
}
453
454
// Handle pagination edge cases
455
public IPage<User> getUsersSafely(int current, int size) {
456
// Ensure valid parameters
457
current = Math.max(1, current);
458
size = Math.min(Math.max(1, size), 100);
459
460
Page<User> page = new Page<>(current, size);
461
IPage<User> result = userService.page(page);
462
463
// Check if current page exceeds total pages
464
if (result.getCurrent() > result.getPages() && result.getPages() > 0) {
465
// Redirect to last page
466
page.setCurrent(result.getPages());
467
result = userService.page(page);
468
}
469
470
return result;
471
}
472
```
473
474
**Performance Considerations:**
475
476
- Use `searchCount = false` when total count is not needed
477
- Optimize count queries by setting `optimizeCountSql = true`
478
- Set reasonable max limits to prevent large queries
479
- Use appropriate indexes for ORDER BY columns
480
- Consider using cursor-based pagination for very large datasets
481
- Cache count results for frequently accessed data