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的,所以实际的需要+1 if (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
对象获取分页查询的各种信息。