#踩雷问题记录 #MyBatis #分页查询 #Java
问题描述
在使用 MyBatis 搭配 PageHelper 分页插件时,接口请求 GET /aigc/app/query-apps?categoryId=1907635448432992257&pageNum=1&pageSize=6
本应返回6条记录,但实际返回了8条记录,pageSize
字段也变成了8。也就是说,分页功能未生效,多返回了数据。
经仔细检查,是因为mapper.xml
中使用了比较复杂的联合查询逻辑,导致PageHelper
插件失效。
原因分析
❗PageHelper 没有真正拦截分页 SQL
这类问题在使用 PageHelper
+ UNION ALL
的 SQL 时非常典型。
PageHelper 会在 MyBatis 执行语句前拦截构造 SQL,自动添加 LIMIT
。但如果你的 XML 中包含某些结构(如 UNION ALL
、动态 SQL、复杂嵌套子查询),PageHelper 可能会提前查询完整数据(不分页),然后再进行内存分页(即 Java 代码中分页,而不是数据库分页)。
解决方式
询问了Gpt,尝试使用了”使用子查询包裹 UNION ALL
,让 PageHelper 正确识别分页点“方式,未能成功解决。
最后采用的方式是手写分页查询,赋值给PageInfo
。以下是文件的一些改动:
mapper.xml
: 在select结尾加上LIMIT和OFFSET
LIMIT #{pageSize} OFFSET #{offset}
xxxServiceImpl.java
: 计算offset, total, 总页数,是否有上一页,是否有下一页等PageInfo
信息
// PageHelper.startPage(pageNum, pageSize); 之前的PageHelper已经失效
int offset = (pageNum - 1) * pageSize;
List<AigcAppWithCategoryDTO> list = aigcAppMapper.selectAppsWithCategoryByCategoryId(categoryId,offset, pageSize);
PageInfo<AigcAppWithCategoryDTO> pageInfo = new PageInfo<>();
pageInfo.setList(list);
pageInfo.setPageNum(pageNum);
pageInfo.setPageSize(pageSize);
pageInfo.setTotal(total);
pageInfo.setPages((total + pageSize - 1) / pageSize); // 计算总页数
pageInfo.setHasPreviousPage(pageNum > 1); // 是否有上一页
pageInfo.setHasNextPage(pageNum < pageInfo.getPages()); // 是否有下一页
return pageInfo;