
分页接口在后台系统里几乎天天写,但很多人都有一个共同感受:参数没问题、代码也能跑,结果却一会儿对一会儿不对。 同一页数据刷新会变、翻页会重复、偶尔还少数据。问题往往不在分页参数,而是在分页背后的执行方式和写法细节。
本篇文章将直接围绕真实项目里最容易踩的几个点,一条一条拆清楚,并给出可以直接落地的解决方案。

1 问题:分页查询没写排序
现象
- 第 1 页刷新后顺序变化
- 翻到第 2 页,发现有数据重复或消失
原因
数据库在没有 order by 的情况下,返回结果本身就是不保证顺序的。分页只是对“当前返回结果”截取一段,并不会帮你排序。
解决方案
所有分页查询,必须显式指定排序。
Page<User> page = new Page<>(current, size);
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.orderByDesc(User::getCreateTime);
userMapper.selectPage(page, wrapper);
在实际项目里,可以直接把这条当成底线规则:没有排序的分页查询,等同于 Bug。

2 问题:排序字段不唯一
现象
- 翻页时偶发重复数据
- 同一条记录有时出现在上一页,有时出现在下一页
原因
排序字段存在大量相同值,比如:
数据库在这些记录之间没有稳定顺序,分页自然会漂。
解决方案
排序字段必须保证唯一性,或组合排序。
wrapper
.orderByDesc(User::getCreateTime)
.orderByAsc(User::getId);
实践中最稳妥的写法是:业务排序字段 + 主键兜底排序。

3 问题:排序字段本身会变化
现象
- 翻页过程中顺序发生变化
- 刚刚还在第一页的数据,下一次请求跑到后面去了
原因
分页过程中,排序字段被更新了,例如:
数据在你翻页时发生变化,分页结果自然不稳定。
解决方案
分页排序尽量使用静态字段,避免使用实时变化字段。
不推荐:
orderByDesc(updateTime);
更稳妥的方式:
orderByDesc(createTime)
.orderByAsc(id);
如果业务必须使用动态字段排序,就要接受分页不稳定是正常现象。

4 问题:分页过程中查询条件发生变化
现象
- 第一页和第二页使用的条件不完全一致
- 翻页后总数变化,数据错位
原因
分页本质是:同一组条件 + 不同 offset
一旦条件变化,分页语义就被破坏。
解决方案
分页过程中,必须保证:
常见做法是:前端分页参数 + 查询条件整体缓存,或由后端统一封装查询对象。

5 问题:多表查询直接分页
现象
- 单表分页正常,多表分页异常
- order by 看起来没问题,结果却乱
原因
多表 join 后,数据库执行顺序可能被打乱,分页实际上作用在 join 之后的结果集 上。
解决方案
先确定主表顺序,再分页。
推荐思路:
- 先分页查主表 ID
- 再根据 ID 查关联数据
// 第一步:分页查主表
Page<Order> page = orderMapper.selectPage(page, wrapper);
// 第二步:根据 ID 查详情
List<Long> ids = page.getRecords()
.stream()
.map(Order::getId)
.toList();

6 问题:分页查询和总数统计混在一起
现象
原因
复杂查询下,count 和 list 使用了不同条件或不同 join。
解决方案
确保分页查询和总数统计条件完全一致。
在复杂场景中,甚至可以拆成两次明确查询,而不是依赖自动 count。

7 推荐的稳定分页写法
这是一个在后台系统里非常稳的通用写法:
Page<User> page = new Page<>(current, size);
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.eq(User::getStatus, 1)
.orderByDesc(User::getCreateTime)
.orderByAsc(User::getId);
userMapper.selectPage(page, wrapper);
这个组合解决了:

8 分页为什么“看起来对,其实不稳”
从数据库角度看,分页本质是:
select ...
from table
where ...
order by ...
limit offset, size;
只要排序不稳定,分页一定不稳定。 这不是框架问题,而是数据执行层面的事实。
写在最后
分页不稳定,90% 不是参数问题,而是:
一旦你站在 SQL 执行顺序的角度看分页,这些问题基本都会自己暴露出来。掌握正确的Java分页实践,是构建稳定后台服务的基本功。

本文旨在分享分页查询的稳定性实践经验,更多后端开发与数据库相关深度讨论,欢迎访问云栈社区进行交流。