PageHelper分页失效,只能查出第一页
- 1. 现象
- 2. 原因
- 3. PageHelper工作原理
1. 现象
-
分页代码如下:
int pageId = Constants.ONE;boolean isHasNextPage;do {PageHelper.startPage(pageId, Constants.DEFAULT_PAGE_SIZE);List<String> projectIdList = marketingConsStageDAO.getAllProjectId();PageInfo<String> pageInfo = new PageInfo<>(projectIdList);// 此处省略业务逻辑isHasNextPage = pageInfo.isHasNextPage();pageId++;} while (isHasNextPage);
-
marketingConsStageDAO.getAllProjectId()
代码如下:public List<String> getAllProjectId() {Weekend<MarketingConsStage> weekend = Weekend.of(MarketingConsStage.class, true, true);weekend.selectProperties("projectId");weekend.setDistinct(true);return marketingConsStageMapper.selectByExample(weekend).stream().map(MarketingConsStage::getProjectId).collect(Collectors.toList());}
-
marketingConsStageDAO.getAllProjectId()
应该返回两万余条数据,因此预期do-while
循环会执行很多次,但是发现第一页的isHasNextPage
就为false
,无法继续执行do-while
循环;
2. 原因
-
进行
debug
,将断点打到PageInfo<String> pageInfo = new PageInfo<>(projectIdList);
这一行,然后发现返回的
projectIdList
是ArrayList
类型; -
看一下
PageInfo
的构造方法:/*** 包装Page对象** @param list page结果* @param navigatePages 页码数量*/public PageInfo(List<T> list, int navigatePages) {super(list);if (list instanceof Page) {Page page = (Page) list;this.pageNum = page.getPageNum();this.pageSize = page.getPageSize();this.pages = page.getPages();this.size = page.size();//由于结果是>startRow的,所以实际的需要+1if (this.size == 0) {this.startRow = 0;this.endRow = 0;} else {this.startRow = page.getStartRow() + 1;//计算实际的endRow(最后一页的时候特殊)this.endRow = this.startRow - 1 + this.size;}} else if (list instanceof Collection) {this.pageNum = 1;this.pageSize = list.size();this.pages = this.pageSize > 0 ? 1 : 0;this.size = list.size();this.startRow = 0;this.endRow = list.size() > 0 ? list.size() - 1 : 0;}if (list instanceof Collection) {calcByNavigatePages(navigatePages);}}
-
可以看到,由于
projectIdList
是ArrayList
类型,因此在创建pageInfo
对象时,总页数直接走了this.pages = this.pageSize > 0 ? 1 : 0;
的逻辑,导致分页失效; -
如果我们将
.stream() .map(MarketingConsStage::getProjectId) .collect(Collectors.toList());
操作放到分页查询操作外面,将代码修改为:
int pageId = Constants.ONE;boolean isHasNextPage;do {PageHelper.startPage(pageId, Constants.DEFAULT_PAGE_SIZE);List<MarketingConsStage> marketingConsStageList = marketingConsStageDAO.getAllProjectId();PageInfo<MarketingConsStage> pageInfo = new PageInfo<>(marketingConsStageList);List<String> projectIdList = marketingConsStageList.stream().map(MarketingConsStage::getProjectId).collect(Collectors.toList());// 此处省略业务逻辑isHasNextPage = pageInfo.isHasNextPage();pageId++;} while (isHasNextPage);
将
marketingConsStageDAO.getAllProjectId()
修改为:public List<MarketingConsStage> getAllProjectId() {Weekend<MarketingConsStage> weekend = Weekend.of(MarketingConsStage.class, true, true);weekend.selectProperties("projectId");weekend.setDistinct(true);return marketingConsStageMapper.selectByExample(weekend);}
然后
debug
就会发现,marketingConsStageList
是一个Page
类型变量,此时分页功能就正常了;
3. PageHelper工作原理
PageHelper
是一个MyBatis
分页插件,它可以帮助我们在查询数据的时候进行分页处理。当我们调用PageHelper.startPage(pageNum, pageSize)
方法时,它会在底层使用ThreadLocal
来保存当前线程的分页参数,然后通过拦截器对SQL
语句进行改写,从而实现分页查询。- 在我们调用完
PageHelper.startPage(pageNum, pageSize)
方法后,紧接着执行的SQL
查询语句会被PageHelper
拦截并进行改写,从而在查询结果的时候只返回指定页数和每页记录数的数据。PageHelper
会将查询结果封装成一个Page
对象,这个Page
对象包含了查询结果的总记录数、当前页数、每页记录数以及查询结果的数据列表。 - 因此,当我们调用查询方法后,返回的
list
可以被PageHelper
包装成Page
对象。这是因为PageHelper
在底层对查询结果进行了封装,将查询结果以Page
对象的形式返回给了调用方。调用方可以通过Page
对象获取查询结果的各种信息,如总记录数、当前页数、每页记录数等,同时也可以通过Page
对象获取查询结果的数据列表。 - 总之,通过
PageHelper
实现分页查询的过程可以概括为:开启分页查询 -> 执行查询操作 -> 将查询结果列表返回给调用方,并以Page
对象的形式包装 -> 调用方通过Page
对象获取分页查询的各种信息。