MyBatis-Flex is an elegant enhancement framework for MyBatis providing type-safe query building, active record patterns, and comprehensive ORM capabilities
—
Comprehensive pagination with performance optimizations, count query optimization, and type conversion support. MyBatis-Flex provides efficient pagination for large datasets with database-specific optimizations.
Comprehensive pagination object that encapsulates pagination parameters, results, and metadata.
/**
* Comprehensive pagination object
* @param <T> Record type
*/
public class Page<T> {
/**
* Create page with page number and size
* @param pageNumber page number (1-based)
* @param pageSize number of records per page
*/
public Page(int pageNumber, int pageSize);
/**
* Create page with count query optimization setting
* @param pageNumber page number (1-based)
* @param pageSize number of records per page
* @param optimizeCountQuery whether to optimize count query
*/
public Page(int pageNumber, int pageSize, boolean optimizeCountQuery);
/**
* Get current page records
* @return list of records for current page
*/
public List<T> getRecords();
/**
* Set current page records
* @param records records to set
*/
public void setRecords(List<T> records);
/**
* Get total number of records
* @return total record count
*/
public long getTotalRow();
/**
* Set total number of records
* @param totalRow total record count
*/
public void setTotalRow(long totalRow);
/**
* Get total number of pages
* @return total page count
*/
public int getTotalPage();
/**
* Get current page number (1-based)
* @return current page number
*/
public int getPageNumber();
/**
* Set current page number
* @param pageNumber page number to set
*/
public void setPageNumber(int pageNumber);
/**
* Get page size
* @return number of records per page
*/
public int getPageSize();
/**
* Set page size
* @param pageSize records per page
*/
public void setPageSize(int pageSize);
/**
* Check if count query optimization is enabled
* @return true if optimization enabled
*/
public boolean isOptimizeCountQuery();
/**
* Set count query optimization
* @param optimizeCountQuery optimization flag
*/
public void setOptimizeCountQuery(boolean optimizeCountQuery);
/**
* Check if there is a previous page
* @return true if has previous page
*/
public boolean hasPrevious();
/**
* Check if there is a next page
* @return true if has next page
*/
public boolean hasNext();
/**
* Get offset for current page (0-based)
* @return record offset
*/
public long getOffset();
/**
* Convert page to different type
* @param mapper function to convert records
* @return new page with converted records
*/
public <R> Page<R> convert(Function<T, R> mapper);
/**
* Convert page using list transformation
* @param records new records list
* @return new page with provided records
*/
public <R> Page<R> convert(List<R> records);
}Basic Pagination Usage:
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
public class BasicPaginationExample {
public void demonstrateBasicPagination() {
UserMapper userMapper = // ... get mapper instance
// Create page parameters (page 1, 10 records per page)
Page<User> page = new Page<>(1, 10);
// Execute paginated query
QueryWrapper query = QueryWrapper.create()
.select()
.from(User.class)
.where(USER.ACTIVE.eq(true))
.orderBy(USER.CREATE_TIME.desc());
Page<User> result = userMapper.paginate(page, query);
// Access pagination information
System.out.println("Current page: " + result.getPageNumber());
System.out.println("Page size: " + result.getPageSize());
System.out.println("Total records: " + result.getTotalRow());
System.out.println("Total pages: " + result.getTotalPage());
System.out.println("Has next page: " + result.hasNext());
System.out.println("Has previous page: " + result.hasPrevious());
// Access current page records
List<User> users = result.getRecords();
for (User user : users) {
System.out.println("User: " + user.getName());
}
}
}Advanced pagination features for performance optimization in large datasets.
/**
* Performance-optimized pagination options
*/
public class Page<T> {
/**
* Enable/disable count query optimization
* When enabled, skips total count query for better performance
* @param optimizeCountQuery optimization flag
*/
public void setOptimizeCountQuery(boolean optimizeCountQuery);
/**
* Set search count flag
* When false, skips count query entirely
* @param searchCount whether to perform count query
*/
public void setSearchCount(boolean searchCount);
/**
* Check if search count is enabled
* @return true if count query will be performed
*/
public boolean isSearchCount();
/**
* Set custom count query SQL
* @param countSql custom count SQL
*/
public void setCountSql(String countSql);
/**
* Get custom count query SQL
* @return custom count SQL or null
*/
public String getCountSql();
}Performance Optimization Examples:
public class PaginationOptimizationExample {
public void demonstrateOptimizations() {
UserMapper userMapper = // ... get mapper instance
// Standard pagination with count query
Page<User> standardPage = new Page<>(1, 10);
Page<User> standardResult = userMapper.paginate(standardPage, query);
// Executes both data query and count query
// Optimized pagination (skips unnecessary count operations)
Page<User> optimizedPage = new Page<>(1, 10, true);
Page<User> optimizedResult = userMapper.paginate(optimizedPage, query);
// Optimizes count query for better performance
// Skip count query entirely for performance
Page<User> noCountPage = new Page<>(1, 10);
noCountPage.setSearchCount(false);
Page<User> noCountResult = userMapper.paginate(noCountPage, query);
// Only executes data query, no count query
System.out.println("Total rows: " + noCountResult.getTotalRow()); // Will be 0
// Custom count query for complex scenarios
Page<User> customCountPage = new Page<>(1, 10);
customCountPage.setCountSql("SELECT COUNT(*) FROM users u WHERE u.active = 1");
Page<User> customCountResult = userMapper.paginate(customCountPage, query);
// Uses custom count SQL instead of generated one
}
}Convert pagination results to different types while maintaining pagination metadata.
/**
* Type conversion methods for pagination results
*/
public class Page<T> {
/**
* Convert page records using mapper function
* @param mapper function to transform each record
* @return new page with converted records
*/
public <R> Page<R> convert(Function<T, R> mapper);
/**
* Convert page records using provided list
* @param records new records list
* @return new page with provided records
*/
public <R> Page<R> convert(List<R> records);
}Type Conversion Examples:
public class PaginationConversionExample {
public void demonstrateConversion() {
// Original pagination with User entities
Page<User> userPage = userMapper.paginate(
new Page<>(1, 10),
QueryWrapper.create()
.select()
.from(User.class)
.where(USER.ACTIVE.eq(true))
);
// Convert to DTO using mapper function
Page<UserDTO> dtoPage = userPage.convert(user -> {
UserDTO dto = new UserDTO();
dto.setId(user.getId());
dto.setName(user.getName());
dto.setEmail(user.getEmail());
dto.setDisplayName(user.getName() + " (" + user.getEmail() + ")");
return dto;
});
// Pagination metadata is preserved
System.out.println("DTO Page - Total: " + dtoPage.getTotalRow());
System.out.println("DTO Page - Pages: " + dtoPage.getTotalPage());
// Convert using pre-built list
List<UserSummary> summaries = userPage.getRecords().stream()
.map(user -> new UserSummary(user.getId(), user.getName()))
.collect(Collectors.toList());
Page<UserSummary> summaryPage = userPage.convert(summaries);
// Method chaining with conversion
Page<String> nameOnlyPage = userPage.convert(User::getName);
List<String> userNames = nameOnlyPage.getRecords();
}
}Pagination support in service layer with enhanced functionality.
/**
* Service layer pagination methods
*/
public interface IService<T> {
/**
* Paginate all entities
* @param page pagination parameters
* @return page of entities
*/
Page<T> page(Page<T> page);
/**
* Paginate entities with query conditions
* @param page pagination parameters
* @param queryWrapper query conditions
* @return page of entities
*/
Page<T> page(Page<T> page, QueryWrapper queryWrapper);
/**
* Paginate with type transformation
* @param page pagination parameters
* @param queryWrapper query conditions
* @param asType target type class
* @return page of transformed objects
*/
<R> Page<R> pageAs(Page<R> page, QueryWrapper queryWrapper, Class<R> asType);
}Service Layer Pagination Examples:
@Service
public class UserServiceImpl implements UserService {
public Page<UserDTO> getActiveUsers(int pageNum, int pageSize) {
Page<User> page = new Page<>(pageNum, pageSize);
// Service layer pagination
Page<User> userPage = page(page,
QueryWrapper.create()
.from(User.class)
.where(USER.ACTIVE.eq(true))
.orderBy(USER.CREATE_TIME.desc())
);
// Convert to DTO
return userPage.convert(this::convertToDTO);
}
public Page<UserSummaryDTO> getUserSummaries(int pageNum, int pageSize, String nameFilter) {
Page<UserSummaryDTO> page = new Page<>(pageNum, pageSize);
QueryWrapper query = QueryWrapper.create()
.select(USER.ID, USER.NAME, USER.EMAIL, USER.CREATE_TIME)
.from(User.class)
.where(USER.ACTIVE.eq(true));
if (nameFilter != null && !nameFilter.isEmpty()) {
query.and(USER.NAME.like("%" + nameFilter + "%"));
}
// Direct type transformation in service
return pageAs(page, query, UserSummaryDTO.class);
}
private UserDTO convertToDTO(User user) {
UserDTO dto = new UserDTO();
dto.setId(user.getId());
dto.setName(user.getName());
dto.setEmail(user.getEmail());
dto.setAge(user.getAge());
dto.setCreateTime(user.getCreateTime());
return dto;
}
}MyBatis-Flex automatically generates database-specific pagination SQL for optimal performance.
/**
* Database-specific pagination is handled automatically by dialects
* No additional configuration required
*/
public class DatabaseSpecificPagination {
public void demonstrateDatabaseSpecificPagination() {
Page<User> page = new Page<>(2, 15); // Page 2, 15 records per page
QueryWrapper query = QueryWrapper.create()
.select()
.from(User.class)
.where(USER.ACTIVE.eq(true))
.orderBy(USER.NAME.asc());
// MyBatis-Flex generates database-specific SQL:
// MySQL/PostgreSQL/H2:
// SELECT * FROM users WHERE active = 1 ORDER BY name ASC LIMIT 15 OFFSET 15
// SQL Server 2012+:
// SELECT * FROM users WHERE active = 1 ORDER BY name ASC
// OFFSET 15 ROWS FETCH NEXT 15 ROWS ONLY
// Oracle 12c+:
// SELECT * FROM users WHERE active = 1 ORDER BY name ASC
// OFFSET 15 ROWS FETCH NEXT 15 ROWS ONLY
// Oracle (traditional):
// SELECT * FROM (
// SELECT ROWNUM rn, t.* FROM (
// SELECT * FROM users WHERE active = 1 ORDER BY name ASC
// ) t WHERE ROWNUM <= 30
// ) WHERE rn > 15
Page<User> result = userMapper.paginate(page, query);
}
}Convenient methods for pagination navigation and metadata.
/**
* Navigation and metadata helper methods
*/
public class Page<T> {
/**
* Check if current page is first page
* @return true if first page
*/
public boolean isFirstPage();
/**
* Check if current page is last page
* @return true if last page
*/
public boolean isLastPage();
/**
* Get previous page number (null if no previous)
* @return previous page number or null
*/
public Integer getPreviousPage();
/**
* Get next page number (null if no next)
* @return next page number or null
*/
public Integer getNextPage();
/**
* Calculate page numbers for pagination UI
* @param displayCount number of page links to display
* @return list of page numbers for UI
*/
public List<Integer> getPageNumbers(int displayCount);
/**
* Get start record number (1-based)
* @return start record number
*/
public long getStartRow();
/**
* Get end record number (1-based)
* @return end record number
*/
public long getEndRow();
}Navigation Examples:
public class PaginationNavigationExample {
public void demonstrateNavigation() {
Page<User> result = userMapper.paginate(new Page<>(3, 10), query);
// Navigation checks
System.out.println("Is first page: " + result.isFirstPage()); // false
System.out.println("Is last page: " + result.isLastPage()); // depends on data
System.out.println("Has previous: " + result.hasPrevious()); // true
System.out.println("Has next: " + result.hasNext()); // depends on data
// Page numbers
Integer prevPage = result.getPreviousPage(); // 2
Integer nextPage = result.getNextPage(); // 4 or null
// UI pagination helper
List<Integer> pageNumbers = result.getPageNumbers(5);
// For page 3: [1, 2, 3, 4, 5] or similar range
// Record range
System.out.println("Showing records " + result.getStartRow() +
" to " + result.getEndRow() +
" of " + result.getTotalRow());
// Output: "Showing records 21 to 30 of 157"
}
}// Core pagination types
public class Page<T> {
public Page(int pageNumber, int pageSize);
public Page(int pageNumber, int pageSize, boolean optimizeCountQuery);
public List<T> getRecords();
public long getTotalRow();
public int getTotalPage();
public int getPageNumber();
public int getPageSize();
public <R> Page<R> convert(Function<T, R> mapper);
}
// Functional interface for conversion
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
// Standard Java collections
public interface List<E> extends Collection<E> {
E get(int index);
int size();
boolean isEmpty();
}
// Optional for navigation
public interface Optional<T> {
boolean isPresent();
T get();
T orElse(T other);
}Install with Tessl CLI
npx tessl i tessl/maven-com-mybatis-flex--mybatis-flex-core