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 深分页,相信这个项目会对你有帮助。

相关推荐
qq_12498707533 小时前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
Coder_Boy_3 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
2301_818732063 小时前
前端调用控制层接口,进不去,报错415,类型不匹配
java·spring boot·spring·tomcat·intellij-idea
汤姆yu6 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
暮色妖娆丶7 小时前
Spring 源码分析 单例 Bean 的创建过程
spring boot·后端·spring
biyezuopinvip8 小时前
基于Spring Boot的企业网盘的设计与实现(任务书)
java·spring boot·后端·vue·ssm·任务书·企业网盘的设计与实现
JavaGuide8 小时前
一款悄然崛起的国产规则引擎,让业务编排效率提升 10 倍!
java·spring boot
figo10tf9 小时前
Spring Boot项目集成Redisson 原始依赖与 Spring Boot Starter 的流程
java·spring boot·后端
zhangyi_viva9 小时前
Spring Boot(七):Swagger 接口文档
java·spring boot·后端
橙露9 小时前
Spring Boot 核心原理:自动配置机制与自定义 Starter 开发
java·数据库·spring boot