简介:本文深入解析MyBatis-Plus分页查询的实现原理与最佳实践,涵盖基础配置、核心API使用、性能优化策略及常见问题解决方案。通过代码示例与场景分析,帮助开发者快速掌握分页功能开发技巧。
在Web应用开发中,分页查询是处理大数据集的核心功能。传统MyBatis实现需手动编写分页SQL,存在以下痛点:
MyBatis-Plus作为MyBatis的增强工具,通过内置分页插件解决了这些问题。其核心优势包括:
MyBatis-Plus 3.x版本推荐使用MybatisPlusInterceptor进行配置:
@Configurationpublic class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}}
关键配置项说明:
DbType:指定数据库类型(MySQL/Oracle/PostgreSQL等)maxLimit:单页最大记录数限制(防全表扫描)overflow:页码溢出处理策略Page类是分页查询的核心参数对象,包含三个核心属性:
// 当前页码(从1开始)private long current;// 每页显示条数private long size;// 排序条件(可多字段)private List<OrderItem> orders;// 自动计算的总页数private transient Long pages;// 查询总数private transient Long total;// 结果集private transient List<T> records;
标准分页查询方法示例:
@Servicepublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {@Overridepublic Page<User> queryUserPage(Page<User> page, String name) {// 构造查询条件QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.like("name", name);// 执行分页查询return baseMapper.selectPage(page, wrapper);}}
RESTful接口实现示例:
@RestController@RequestMapping("/users")public class UserController {@Autowiredprivate UserService userService;@GetMapping("/page")public Result<Page<User>> getUserPage(@RequestParam(defaultValue = "1") Long current,@RequestParam(defaultValue = "10") Long size,@RequestParam(required = false) String name) {Page<User> page = new Page<>(current, size);Page<User> userPage = userService.queryUserPage(page, name);return Result.success(userPage);}}
对于关联查询场景,建议采用两种方案:
子查询分页(推荐):
public Page<UserVO> queryUserWithRolePage(Page<UserVO> page, String keyword) {// 先执行分页查询Page<User> userPage = baseMapper.selectPage(page,new QueryWrapper<User>().like("username", keyword));// 再处理关联数据(示例伪代码)List<UserVO> vos = userPage.getRecords().stream().map(user -> {UserVO vo = new UserVO();BeanUtils.copyProperties(user, vo);Role role = roleService.getByUserId(user.getId());vo.setRoleName(role.getName());return vo;}).collect(Collectors.toList());return new Page<>(userPage.getCurrent(), userPage.getSize(),userPage.getTotal(), vos);}
使用SQL JOIN(需注意性能):
对于复杂查询场景,可通过XML映射文件实现:
<select id="selectCustomPage" resultType="map">SELECT * FROM (SELECT a.*, ROW_NUMBER() OVER (ORDER BY ${ew.sqlSort}) as row_numFROM user a${ew.customSqlSegment}) tempWHERE row_num BETWEEN #{page.current}*#{page.size}-#{page.size}+1AND #{page.current}*#{page.size}</select>
EXPLAIN估算行数ORDER BY大字段现象:总记录数与实际结果不符
原因:
// 使用selectCount方法显式指定计数SQLwrapper.select("DISTINCT user_id"); // 去重long count = baseMapper.selectCount(wrapper);
诊断工具:
优化案例:
// 优化前(全表扫描)wrapper.eq("status", 1).orderByDesc("create_time");// 优化后(索引利用)wrapper.eq("status", 1).last("ORDER BY create_time DESC LIMIT 1000000,10"); // 深度分页优化
分页大小设计:
安全防护:
// 限制最大分页大小public Page<User> safeQuery(Page<User> page) {if (page.getSize() > 100) {page.setSize(100);}return baseMapper.selectPage(page, null);}
测试用例设计:
| MyBatis-Plus版本 | 分页插件变化 | 注意事项 |
|---|---|---|
| 3.0.x | 新增拦截器机制 | 需移除旧版分页插件配置 |
| 3.4.x | 优化COUNT查询 | 支持多数据源分页 |
| 3.5.x | 性能提升20% | 推荐使用最新稳定版 |
动态表分页:
多租户分页:
@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {@Overridepublic Expression getTenantId() {return new LongValue(1L); // 租户ID}@Overridepublic String getTenantIdColumn() {return "tenant_id";}}));interceptor.addInnerInterceptor(new PaginationInnerInterceptor());return interceptor;}
MyBatis-Plus分页功能通过拦截器机制实现了优雅的分页解决方案,其核心价值体现在:
未来发展方向可能包括:
建议开发者在使用过程中注意:
通过掌握本文介绍的技术要点和最佳实践,开发者可以高效实现稳定可靠的分页查询功能,为系统性能优化和用户体验提升奠定坚实基础。