PageHelper-Cursor:支持游标分页的 PageHelper 修改版,解决 MyBatis 深分页性能问题

PageHelper-Cursor:支持游标分页的 PageHelper 修改版,解决 MyBatis 深分页性能问题

在 MyBatis 项目中,PageHelper是常用的分页插件,它默认采用 LIMIT offset size`的传统物理分页方式 。这种分页很容易在大数据量表中触发深分页性能问题:当 pageNum 越来越大,SQL 执行性能呈指数级下滑,offset 越大扫描代价越高。

举个例子:

sql 复制代码
SELECT * FROM user ORDER BY id LIMIT 1000000, 20;

这种 SQL 将会导致 MySQL 扫描百万级数据后再丢弃数据,拖垮查询性能。

那么有没有更优雅、更高性能的分页方式?

答案是:有!那就是"游标分页"(Cursor Pagination)。


PageHelper-Cursor 是什么?

PageHelper-Cursor 是基于 PageHelper 6.1.1 改造的版本,增加了 游标分页能力 ,通过一个有序索引字段充当分页游标 ,绕开了 OFFSET 带来的扫描成本,从而高效支持深分页。

github链接,文档齐全:Cursor-PageHelper: Mybatis通用分页插件

部署指南:BUILD_AND_DEPLOY_GUIDE.md

✅ 特性总结:

特性 支持
避免深分页性能问题 ✅
兼容 PageHelper 使用体验 ✅
支持 MySQL & PostgreSQL ✅
支持字段游标分页 ✅
使用简单 ✅

🚨 注意:该版本目前为非常早期的测试版,性能和可靠性无法保证,强烈建议不要用于生产环境。


为什么游标分页能解决深分页?

游标分页的核心思想:

不再跳过前面所有数据,而是根据上一个查询返回的最后一个字段作为游标继续往后查。

例如:

sql 复制代码
-- 第一次查询 
SELECT * FROM user WHERE id > 0 ORDER BY id LIMIT 20; 
-- 下一次查询,从最后一个 id 开始继续 
SELECT * FROM user WHERE id > 1020 ORDER BY id LIMIT 20;

这种做法依赖索引查找,不会扫全表,性能几乎是常数级的 O(1)。


引入 PageHelper-Cursor

如果你的项目是 Spring Boot + MyBatis,在本地部署打包后直接加入下面依赖即可:

xml 复制代码
<!--PageHelper SpringBoot 整合-->
<dependency> 
    <groupId>com.github.pagehelper</groupId> 
    <artifactId>pagehelper-spring-boot-starter</artifactId> 
    <version>${pagehelper-spring-boot-starter.version}</version>
</dependency> 

<!--PageHelper Cursor 测试版--> 
<dependency>
    <groupId>com.github.pagehelper</groupId> 
    <artifactId>pagehelper</artifactId>
    <version>6.1.1-cursor-SNAPSHOT</version> 
</dependency>`

⚠️ 环境要求:最好是MyBatis 3.1.0+


使用示例

✅ 例1:基于自增 ID 分页(最简单)

java 复制代码
@RestController
@RequestMapping("/api/users") 
public class UserController { 
    
    @Autowired private UserMapper userMapper;
    
    @GetMapping public PageInfo<User> getUsers( 
            @RequestParam(required = false, defaultValue = "0") Long cursor) { 
            // 使用游标分页 
            PageHelper.startCursor("id", cursor, 20); 
            List<User> users = userMapper.selectAll(); 
            return new PageInfo<>(users); 
    } 
}

前端分页请求示例:

javascript 复制代码
GET /api/users?cursor=0 GET /api/users?cursor=1001

✅ 例2:使用 create_time 游标分页(更通用)

java 复制代码
@GetMapping("/listWithCursor") 
@Tag(name = "获取所有评论信息", description = "管理员分页获取当前所有评论信息列表") 
public Result<List<TopCommentVo>> queryWithCursor( 
        @RequestParam(required = false) String keyWord, 
        @RequestParam(defaultValue = "0") String lastDate, 
        @RequestParam(defaultValue = "10") int pageSize) { 
    if(lastDate.equals("0")){ 
        lastDate = null; 
    } 
    // 开启分页 
    PageHelper.startCursor("c.create_time",lastDate,pageSize,false); // 执行查询 
    List<TopCommentVo> list = commentService.query(keyWord); 
    // 获取分页信息 
    PageInfo<TopCommentVo> pageInfo = new PageInfo<>(list); 
    // 清理分页 
    PageHelper.clearPage(); 
    // 使用自定义分页返回方法
    return Result.page(list, pageInfo.getTotal()); 
}

注意事项(必看❗)

✅ 成功使用游标分页必须满足几个条件:

条件 必要性
游标字段必须参与排序,且是第一个排序字段 ✅ 必须
游标字段必须有索引支持 ✅ 强烈推荐
暂不支持任意表达式分页 ✅ 不支持
SQL 如有 ORDER BY 必须与游标字段一致 ✅ 必须

与传统分页对比

对比项 LIMIT 分页 Cursor 分页
深分页性能 ❌ 极差 ✅ 稳定
查询效率 O(N) O(1)
依赖 OFFSET ✅ 是 ❌ 否
是否要求索引 ✅ 推荐 ✅ 强制
数据一致性好 ✅ ⚠️ 依赖排序字段

总结

PageHelper-Cursor为 MyBatis 提供了高性能分页的新选择,在处理海量分页时性能优势非常明显。它特别适合:

✅ 评论流、订单列表

✅ Feed 流、用户动态

✅ 日志查询、时间排序类数据

目前项目处于测试阶段,如果你对性能敏感、希望替换掉 LIMIT 深分页,相信这个项目会对你有帮助。

相关推荐
云-缩影4 小时前
拆解 AI 图像生成应用的后端架构:ECS、OSS 和大模型 API 怎么配合
java·spring boot·后端
AI开源软件6 小时前
SpringBoot3+Vue3 财务管理系统如何设计:从业务单据到总账的模块划分
spring boot·vue3·领域建模·会计凭证·ruoyi office·业财协同·财务系统设计
Mikko711 小时前
Redis 连接数满了服务端有错误信息吗?连接数不增加却命令超时?6.2 实测连接池、超时与大 key 怎么判定
java·spring boot·redis·后端
真上帝的左手14 小时前
30. 技术专题-‌应用框架组件-关系型数据库-MySQL-Mybatis
数据库·分布式·mysql·中间件·mybatis
计算机毕设定制辅导-无忧学长16 小时前
《基于微信小程序健康习惯激励系统设计与实现》
java·spring boot·mysql·微信小程序·uniapp·健康习惯激励系统
vipxieliang17 小时前
ValidX 正则表达式预编译优化:Pattern 复用策略
java·spring boot·后端
雪芽蓝域zzs17 小时前
第 2 章:整合 MySQL + MyBatis,搭建数据库基础、实体类、Mapper、测试查询
数据库·mysql·mybatis
余槐i18 小时前
Spring Boot 3.2 偶发500无日志:线程池复用导致请求上下文丢失
spring boot·redis·后端·mysql·性能优化
杨凯凡18 小时前
Spring Boot 的 @Transactional 为什么会失效?从代理、自调用到异常回滚的排查实战
java·spring boot·spring·事务·后端开发
云创智城-yuncitys1 天前
YunParking 4.0:JDK 17 与 Spring Boot 3.2 的停车云升级
java·开发语言·spring boot