How to Implement Pagination with MyBatis-Flex: Page Queries and Metadata
I needed to display a large dataset in pages rather than loading everything at once. With MyBatis-Flex, I found the paginate() method handles both data retrieval and count calculations in one call.
Basic Pagination
I wanted to get accounts with a specific filter, split into pages. Here’s how I did it:
public interface AccountMapper extends BaseMapper<Account> { // The paginate method is inherited from BaseMapper}// Create a query wrapper with filter conditionQueryWrapper queryWrapper = QueryWrapper.create() .where(ACCOUNT.AGE.ge(18));
// Call paginate: pageNumber=1, pageSize=2Page<Account> page = accountMapper.paginate(1, 2, queryWrapper);
// Get the records for current pageList<Account> records = page.getRecords();
// Get pagination metadatalong totalRow = page.getTotalRow(); // Total matching recordslong totalPage = page.getTotalPage(); // Total pagesWhen I ran this with 5 accounts matching the filter:
Records on page 1: 2Total matching records: 5Total pages: 3The Page<T> object contains both the data and metadata, so I didn’t need to write a separate count query.
Service Layer Method
I wrapped the pagination logic in a service method:
public class AccountService {
private final AccountMapper accountMapper;
public AccountService(AccountMapper accountMapper) { this.accountMapper = accountMapper; }
public Page<Account> findAdultAccounts(int pageNumber, int pageSize) { QueryWrapper queryWrapper = QueryWrapper.create() .where(ACCOUNT.AGE.ge(18));
return accountMapper.paginate(pageNumber, pageSize, queryWrapper); }}This keeps the pagination logic reusable across different controllers.
Controller with Pagination Metadata
In my controller, I used the Page object to build a response with all the information the frontend needs:
@GetMapping("/accounts")public Map<String, Object> getAccounts( @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size) {
Page<Account> result = accountService.findAdultAccounts(page, size);
Map<String, Object> response = new HashMap<>(); response.put("records", result.getRecords()); response.put("totalRow", result.getTotalRow()); response.put("totalPage", result.getTotalPage()); response.put("currentPage", page); response.put("pageSize", size);
return response;}The frontend receives everything it needs to render pagination controls:
{ "records": [...], "totalRow": 5, "totalPage": 3, "currentPage": 1, "pageSize": 2}Common Mistakes I Avoided
Using 0-based page numbering: MyBatis-Flex uses 1-based numbering. The first page is 1, not 0.
Inconsistent filters between count and data queries: Since paginate() applies the same QueryWrapper to both count and data queries, I didn’t have this problem. But if I wrote separate queries, I’d need to ensure the WHERE clauses match exactly.
Not checking page bounds: If a user requests page 10 but there are only 3 pages, getRecords() returns an empty list. I handle this in the frontend by checking totalPage.
Summary
In this post, I showed how to implement pagination in MyBatis-Flex using the paginate() method. The Page<T> object provides both the current page’s records and metadata like getTotalRow() and getTotalPage(). Remember that page numbering starts at 1, not 0.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments