or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

active-record.mdcondition-builders.mdindex.mdkotlin-extensions.mdpagination.mdplugin-system.mdservice-layer.mdstatic-utilities.md

pagination.mddocs/

0

# Pagination

1

2

MyBatis-Plus Extension provides comprehensive pagination support through the `Page` class and `PaginationInnerInterceptor`. The pagination system automatically handles count queries, limit/offset generation, and database-specific SQL dialect differences.

3

4

## Core Components

5

6

### Page Class

7

8

The main pagination container that implements `IPage<T>`.

9

10

```java { .api }

11

public class Page<T> implements IPage<T> {

12

private static final long serialVersionUID = 8545996863226528798L;

13

14

// Core pagination fields

15

private List<T> records = Collections.emptyList();

16

private long total = 0;

17

private long size = 10;

18

private long current = 1;

19

private List<OrderItem> orders = new ArrayList<>();

20

private boolean optimizeCountSql = true;

21

private boolean optimizeJoinOfCountSql = true;

22

private boolean searchCount = true;

23

private boolean hitCount = false;

24

private String countId;

25

private Long maxLimit;

26

27

// Constructors

28

public Page();

29

public Page(long current, long size);

30

public Page(long current, long size, long total);

31

public Page(long current, long size, boolean searchCount);

32

public Page(long current, long size, long total, boolean searchCount);

33

34

// Static factory methods

35

public static <T> Page<T> of(long current, long size);

36

public static <T> Page<T> of(long current, long size, long total);

37

public static <T> Page<T> of(long current, long size, boolean searchCount);

38

39

// Data access methods

40

public List<T> getRecords();

41

public Page<T> setRecords(List<T> records);

42

public long getTotal();

43

public Page<T> setTotal(long total);

44

public long getSize();

45

public Page<T> setSize(long size);

46

public long getCurrent();

47

public Page<T> setCurrent(long current);

48

49

// Navigation methods

50

public long getPages();

51

public long offset();

52

public boolean hasPrevious();

53

public boolean hasNext();

54

55

// Ordering methods

56

public List<OrderItem> orders();

57

public Page<T> addOrder(OrderItem... items);

58

public Page<T> addOrder(List<OrderItem> items);

59

60

// Configuration methods

61

public boolean optimizeCountSql();

62

public Page<T> setOptimizeCountSql(boolean optimizeCountSql);

63

public boolean optimizeJoinOfCountSql();

64

public Page<T> setOptimizeJoinOfCountSql(boolean optimizeJoinOfCountSql);

65

public boolean searchCount();

66

public Page<T> setSearchCount(boolean searchCount);

67

public Long maxLimit();

68

public Page<T> setMaxLimit(Long maxLimit);

69

}

70

```

71

72

### IPage Interface

73

74

The base pagination interface.

75

76

```java { .api }

77

public interface IPage<T> extends Serializable {

78

List<T> getRecords();

79

IPage<T> setRecords(List<T> records);

80

long getTotal();

81

IPage<T> setTotal(long total);

82

long getSize();

83

IPage<T> setSize(long size);

84

long getCurrent();

85

IPage<T> setCurrent(long current);

86

87

// Computed properties

88

default long getPages() {

89

if (getSize() == 0) {

90

return 0L;

91

}

92

long pages = getTotal() / getSize();

93

if (getTotal() % getSize() != 0) {

94

pages++;

95

}

96

return pages;

97

}

98

99

default long offset() {

100

return getCurrent() > 0 ? (getCurrent() - 1) * getSize() : 0;

101

}

102

103

default boolean hasPrevious() {

104

return getCurrent() > 1;

105

}

106

107

default boolean hasNext() {

108

return getCurrent() < getPages();

109

}

110

}

111

```

112

113

### OrderItem Class

114

115

Represents ordering criteria for pagination queries.

116

117

```java { .api }

118

public class OrderItem implements Serializable {

119

private String column;

120

private boolean asc = true;

121

122

public OrderItem();

123

public OrderItem(String column, boolean asc);

124

125

// Static factory methods

126

public static OrderItem asc(String column);

127

public static OrderItem desc(String column);

128

public static List<OrderItem> ascs(String... columns);

129

public static List<OrderItem> descs(String... columns);

130

131

// Getters and setters

132

public String getColumn();

133

public void setColumn(String column);

134

public boolean isAsc();

135

public void setAsc(boolean asc);

136

}

137

```

138

139

### PageDTO Class

140

141

Data Transfer Object for pagination parameters.

142

143

```java { .api }

144

public class PageDTO<T> implements IPage<T> {

145

private List<T> records = Collections.emptyList();

146

private long total = 0;

147

private long size = 10;

148

private long current = 1;

149

150

// Implements IPage methods

151

}

152

```

153

154

## Database Dialects

155

156

MyBatis-Plus Extension supports multiple database dialects for optimal pagination SQL generation.

157

158

### IDialect Interface

159

160

```java { .api }

161

public interface IDialect {

162

boolean willDoCount(IPage<?> page, List<MappedStatement> countMs);

163

String buildPaginationSql(String originalSql, long offset, long limit);

164

}

165

```

166

167

### Available Dialects

168

169

```java { .api }

170

// MySQL/MariaDB

171

public class MySqlDialect implements IDialect;

172

173

// PostgreSQL

174

public class PostgreDialect implements IDialect;

175

176

// Oracle

177

public class OracleDialect implements IDialect;

178

public class Oracle12cDialect implements IDialect;

179

180

// SQL Server

181

public class SQLServerDialect implements IDialect;

182

public class SQLServer2005Dialect implements IDialect;

183

184

// DB2

185

public class DB2Dialect implements IDialect;

186

187

// Other databases

188

public class InformixDialect implements IDialect;

189

public class SybaseDialect implements IDialect;

190

public class GBase8sDialect implements IDialect;

191

public class XCloudDialect implements IDialect;

192

public class TrinoDialect implements IDialect;

193

```

194

195

## Usage Examples

196

197

### Basic Pagination

198

199

```java

200

@Autowired

201

private UserService userService;

202

203

// Create page parameters

204

Page<User> page = new Page<>(1, 10); // page 1, size 10

205

206

// Execute paginated query

207

Page<User> result = userService.page(page);

208

209

// Access results

210

List<User> users = result.getRecords();

211

long totalRecords = result.getTotal();

212

long totalPages = result.getPages();

213

long currentPage = result.getCurrent();

214

long pageSize = result.getSize();

215

216

System.out.println("Found " + totalRecords + " users");

217

System.out.println("Page " + currentPage + " of " + totalPages);

218

```

219

220

### Pagination with Conditions

221

222

```java

223

// Create page with conditions

224

Page<User> page = new Page<>(1, 20);

225

QueryWrapper<User> queryWrapper = new QueryWrapper<User>()

226

.eq("active", true)

227

.like("name", "John");

228

229

Page<User> result = userService.page(page, queryWrapper);

230

231

// Process results

232

for (User user : result.getRecords()) {

233

System.out.println("User: " + user.getName());

234

}

235

```

236

237

### Pagination with Ordering

238

239

```java

240

// Add ordering to pagination

241

Page<User> page = new Page<User>(1, 10)

242

.addOrder(OrderItem.desc("created_time"))

243

.addOrder(OrderItem.asc("name"));

244

245

Page<User> result = userService.page(page);

246

247

// Alternative: using static methods

248

Page<User> page2 = new Page<User>(1, 10)

249

.addOrder(OrderItem.descs("created_time", "updated_time"))

250

.addOrder(OrderItem.ascs("name", "email"));

251

```

252

253

### Static Factory Methods

254

255

```java

256

// Using static factory methods

257

Page<User> page1 = Page.of(1, 10);

258

Page<User> page2 = Page.of(2, 20, 100); // with total count

259

Page<User> page3 = Page.of(1, 15, false); // without count query

260

261

Page<User> result = userService.page(page1);

262

```

263

264

### Navigation Helpers

265

266

```java

267

Page<User> result = userService.page(new Page<>(2, 10));

268

269

// Check navigation state

270

if (result.hasPrevious()) {

271

System.out.println("Previous page available");

272

}

273

274

if (result.hasNext()) {

275

System.out.println("Next page available");

276

}

277

278

// Calculate offset

279

long offset = result.offset(); // (current - 1) * size

280

System.out.println("Offset: " + offset);

281

```

282

283

### Count Query Optimization

284

285

```java

286

// Disable count query for performance

287

Page<User> page = new Page<User>(1, 10)

288

.setSearchCount(false); // No total count query

289

290

Page<User> result = userService.page(page);

291

// result.getTotal() will be 0

292

293

// Optimize count SQL

294

Page<User> optimizedPage = new Page<User>(1, 10)

295

.setOptimizeCountSql(true) // Remove unnecessary ORDER BY in count

296

.setOptimizeJoinOfCountSql(true); // Optimize JOIN queries in count

297

298

// Set max limit to prevent large page sizes

299

Page<User> limitedPage = new Page<User>(1, 1000)

300

.setMaxLimit(500L); // Will be capped at 500

301

```

302

303

### Lambda Query Chains with Pagination

304

305

```java

306

// Using lambda query chains

307

Page<User> page = userService.lambdaQuery()

308

.eq(User::getActive, true)

309

.gt(User::getAge, 18)

310

.orderByDesc(User::getCreatedTime)

311

.page(new Page<>(1, 10));

312

313

List<User> users = page.getRecords();

314

```

315

316

### Chain Wrappers with Pagination

317

318

```java

319

// Using chain wrappers

320

Page<User> page = ChainWrappers.queryChain(userMapper)

321

.eq("department", "IT")

322

.isNotNull("email")

323

.orderByAsc("name")

324

.page(new Page<>(1, 15));

325

```

326

327

### Custom Count Query

328

329

```java

330

// Use custom count query ID

331

Page<User> page = new Page<User>(1, 10)

332

.setCountId("selectUserCountCustom"); // Custom count method

333

334

Page<User> result = userService.page(page, queryWrapper);

335

```

336

337

### Map Results Pagination

338

339

```java

340

// Paginate map results

341

Page<Map<String, Object>> mapPage = new Page<>(1, 10);

342

Page<Map<String, Object>> result = userService.pageMaps(mapPage,

343

new QueryWrapper<User>().select("id", "name", "email"));

344

345

for (Map<String, Object> record : result.getRecords()) {

346

System.out.println("ID: " + record.get("id"));

347

System.out.println("Name: " + record.get("name"));

348

}

349

```

350

351

## Advanced Features

352

353

### Custom Pagination Interceptor Configuration

354

355

```java

356

@Configuration

357

public class PaginationConfig {

358

359

@Bean

360

public MybatisPlusInterceptor mybatisPlusInterceptor() {

361

MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

362

363

PaginationInnerInterceptor paginationInterceptor =

364

new PaginationInnerInterceptor(DbType.MYSQL);

365

366

// Configure options

367

paginationInterceptor.setMaxLimit(1000L); // Max page size

368

paginationInterceptor.setOverflow(false); // Handle page overflow

369

paginationInterceptor.setOptimizeJoin(true); // Optimize JOIN in count

370

371

interceptor.addInnerInterceptor(paginationInterceptor);

372

return interceptor;

373

}

374

}

375

```

376

377

### Custom Dialect

378

379

```java

380

public class CustomDialect implements IDialect {

381

382

@Override

383

public boolean willDoCount(IPage<?> page, List<MappedStatement> countMs) {

384

return page.searchCount();

385

}

386

387

@Override

388

public String buildPaginationSql(String originalSql, long offset, long limit) {

389

// Custom pagination SQL generation

390

return originalSql + " LIMIT " + offset + ", " + limit;

391

}

392

}

393

394

// Register custom dialect

395

@Configuration

396

public class CustomDialectConfig {

397

398

@Bean

399

public MybatisPlusInterceptor mybatisPlusInterceptor() {

400

MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

401

402

PaginationInnerInterceptor paginationInterceptor =

403

new PaginationInnerInterceptor();

404

paginationInterceptor.setDialect(new CustomDialect());

405

406

interceptor.addInnerInterceptor(paginationInterceptor);

407

return interceptor;

408

}

409

}

410

```

411

412

### Performance Optimizations

413

414

```java

415

// For large datasets, disable count query on subsequent pages

416

Page<User> firstPage = new Page<>(1, 50);

417

Page<User> result1 = userService.page(firstPage);

418

419

// Subsequent pages without count

420

Page<User> secondPage = new Page<User>(2, 50)

421

.setSearchCount(false)

422

.setTotal(result1.getTotal()); // Use previous total

423

424

Page<User> result2 = userService.page(secondPage);

425

```

426

427

### Infinite Scroll Pattern

428

429

```java

430

// Implementing infinite scroll

431

public Page<User> getNextPage(Long lastId, int size) {

432

Page<User> page = new Page<User>(1, size)

433

.setSearchCount(false); // No count needed for infinite scroll

434

435

QueryWrapper<User> wrapper = new QueryWrapper<User>()

436

.gt("id", lastId) // Cursor-based pagination

437

.orderByAsc("id");

438

439

return userService.page(page, wrapper);

440

}

441

442

// Usage

443

Page<User> firstBatch = getNextPage(0L, 20);

444

Long lastId = firstBatch.getRecords().get(firstBatch.getRecords().size() - 1).getId();

445

Page<User> nextBatch = getNextPage(lastId, 20);

446

```

447

448

### Error Handling

449

450

```java

451

try {

452

Page<User> page = new Page<>(100, 50); // Potentially invalid page

453

Page<User> result = userService.page(page);

454

455

if (result.getRecords().isEmpty() && result.getCurrent() > 1) {

456

// Handle empty page - might want to redirect to last valid page

457

long lastPage = result.getPages();

458

page.setCurrent(lastPage);

459

result = userService.page(page);

460

}

461

} catch (Exception e) {

462

// Handle pagination errors

463

log.error("Pagination error", e);

464

}

465

```

466

467

## Performance Considerations

468

469

- Use `setSearchCount(false)` when total count is not needed

470

- Enable count query optimizations with `setOptimizeCountSql(true)`

471

- Set reasonable `maxLimit` to prevent memory issues

472

- Consider cursor-based pagination for very large datasets

473

- Use database-appropriate dialects for optimal SQL generation

474

- Cache count results for expensive queries when possible