在Java开发中,MyBatis Plus和PageHelper都是非常流行的MyBatis扩展插件,它们分别提供了便捷的查询封装和分页功能。许多开发者在项目中同时使用这两个插件时,常会遇到分页信息不准确的问题。本文将从常见问题现象出发,分析原因,并提供有效的解决方案,以帮助大家在开发中更好地使用这两个插件。
问题现象
在项目中,我们期望通过PageHelper来分页查询数据,并配合MyBatis Plus的LambdaQueryWrapper进行条件查询。例如:
int pageNum = 2;
int pageSize = 2;
// 配置分页参数
PageHelper.startPage(pageNum, pageSize);
// 使用 MyBatis Plus 的查询封装
LambdaQueryWrapper<DataPerson> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DataPerson::getDelFlag, DelFlagEnum.NORMAL.getCode());
// 使用 selectVoList 查询
List<DataPersonVO> oldPersons = mapper.selectVoList(wrapper);
PageInfo<DataPersonVO> pageInfo = new PageInfo<>(oldPersons);
System.out.println(pageInfo);
按预期,pageInfo中应该显示正确的分页信息,但实际输出显示 pageNum 一直是 1,isLastPage 总是 true,分页不生效。进一步分析SQL发现,selectVoList方法在数据库查询时确实被正确加上了LIMIT分页参数,因此数据集是正确的,但分页对象 PageInfo 的 pageNum 等属性却不正确。
原因分析
PageHelper在MyBatis拦截层添加分页参数,以自动修改生成的SQL。但它的分页上下文信息捕获依赖于标准MyBatis查询,而MyBatis Plus的selectVoList等扩展方法生成SQL的方式有所不同,导致PageHelper在生成PageInfo时没有正确捕获pageNum等分页上下文。
具体原因包括:
-
PageHelper的分页拦截机制:PageHelper依赖于MyBatis生成的SQL查询,以自动在SQL中添加分页参数并生成分页对象,但某些MyBatis Plus特有方法如
selectVoList不一定符合这种机制,可能会导致分页参数未被正确传递。 -
PageHelper和MyBatis Plus方法的兼容性问题:尽管PageHelper能在查询中加入分页参数,但对于MyBatis Plus的扩展方法(如
selectVoList),分页上下文可能未正确传递到PageInfo中,导致页面数据不一致。
解决方案
针对以上问题,我们可以考虑以下几种解决方案:
方案一:使用MyBatis Plus自带的分页插件
MyBatis Plus自带了分页插件,完全支持MyBatis Plus扩展方法如selectVoList,适配性更高,可以确保分页查询和分页信息的一致性。具体步骤如下:
-
确保项目中已配置了MyBatis Plus的分页插件,例如在Spring Boot项目中引入
PaginationInterceptor。 -
使用MyBatis Plus的
Page对象来进行分页查询:import com.baomidou.mybatisplus.extension.plugins.pagination.Page; int pageNum = 2; int pageSize = 2; // 使用 MyBatis Plus 的分页对象 Page<DataPersonVO> page = new Page<>(pageNum, pageSize); // 执行分页查询 page = mapper.selectVoList(page, wrapper); // 获取分页信息 long total = page.getTotal(); // 总记录数 long totalPages = page.getPages(); // 总页数 List<DataPersonVO> data = page.getRecords(); // 当前页数据
使用MyBatis Plus的分页插件可以确保分页数据准确,包括pageNum、isLastPage等分页信息正确显示。
方案二:自定义Mapper方法
如果由于项目限制,无法更换为MyBatis Plus分页插件,可以选择在Mapper中自定义方法,通过编写SQL语句,避免MyBatis Plus的扩展方法干扰PageHelper的分页效果。
-
在
Mapper接口中定义自定义查询方法:List<DataPersonVO> customSelectVoList(@Param("wrapper") Wrapper<DataPerson> wrapper); -
在XML中编写SQL语句:
<select id="customSelectVoList" resultType="DataPersonVO"> SELECT * FROM data_person <where> ${ew.customSqlSegment} </where> </select> -
调用
customSelectVoList并结合PageHelper:PageHelper.startPage(pageNum, pageSize); List<DataPersonVO> oldPersons = mapper.customSelectVoList(wrapper); PageInfo<DataPersonVO> pageInfo = new PageInfo<>(oldPersons);
这种方式可以确保分页效果和分页信息正常显示,但需要手动定义SQL语句。
方案三:使用selectList替代selectVoList
若不需要使用selectVoList方法,可以直接使用MyBatis Plus的selectList方法。selectList方法与PageHelper兼容性更高,能正确生成PageInfo分页数据。
PageHelper.startPage(pageNum, pageSize);
List<DataPersonVO> oldPersons = mapper.selectList(wrapper);
PageInfo<DataPersonVO> pageInfo = new PageInfo<>(oldPersons);
此方法与PageHelper的兼容性更高,PageInfo的分页信息显示也更准确。
方案四:手动分页
在数据量较小的场景下,可以选择手动分页,不依赖分页插件。具体做法是:
- 不使用分页插件,直接查询符合条件的所有数据。
- 手动计算分页偏移量,从结果集中截取分页数据。
List<DataPersonVO> oldPersons = mapper.selectVoList(wrapper);
int fromIndex = (pageNum - 1) * pageSize;
int toIndex = Math.min(fromIndex + pageSize, oldPersons.size());
List<DataPersonVO> pagedResult = oldPersons.subList(fromIndex, toIndex);
手动分页适用于小数据量展示,但不适合大数据量场景。
总结
在MyBatis Plus和PageHelper联合使用时,使用MyBatis Plus的扩展方法(如selectVoList)会导致PageHelper生成的PageInfo信息不准确。以下为总结的几种解决方案:
- 使用MyBatis Plus自带分页插件:推荐方案,与
selectVoList等扩展方法兼容性更好,能直接返回正确分页信息。 - 自定义Mapper方法:可通过编写SQL语句避免MyBatis Plus扩展方法,确保PageHelper分页生效。
- 使用selectList替代selectVoList:若数据结构允许,
selectList能与PageHelper更好兼容。 - 手动分页:适用于小数据量分页展示,但不适合大数据量。
通过合理选择适合的方案,可以有效避免分页信息不准确的问题,提高代码的稳定性和兼容性。希望本文能够帮助大家在项目开发中更好地应用MyBatis Plus与PageHelper,避免类似的分页问题。