找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2019

积分

0

好友

285

主题
发表于 昨天 04:25 | 查看: 8| 回复: 0

章节分隔图标

分页接口在后台系统里几乎天天写,但很多人都有一个共同感受:参数没问题、代码也能跑,结果却一会儿对一会儿不对。 同一页数据刷新会变、翻页会重复、偶尔还少数据。问题往往不在分页参数,而是在分页背后的执行方式和写法细节。

本篇文章将直接围绕真实项目里最容易踩的几个点,一条一条拆清楚,并给出可以直接落地的解决方案

章节分隔图标

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 问题:排序字段不唯一

现象

  • 翻页时偶发重复数据
  • 同一条记录有时出现在上一页,有时出现在下一页

原因

排序字段存在大量相同值,比如:

  • create_time 相同
  • status 相同

数据库在这些记录之间没有稳定顺序,分页自然会漂。

解决方案

排序字段必须保证唯一性,或组合排序。

wrapper
.orderByDesc(User::getCreateTime)
.orderByAsc(User::getId);

实践中最稳妥的写法是:业务排序字段 + 主键兜底排序。

圆球分隔图标

3 问题:排序字段本身会变化

现象

  • 翻页过程中顺序发生变化
  • 刚刚还在第一页的数据,下一次请求跑到后面去了

原因

分页过程中,排序字段被更新了,例如:

  • 按更新时间排序
  • 按点击量排序

数据在你翻页时发生变化,分页结果自然不稳定。

解决方案

分页排序尽量使用静态字段,避免使用实时变化字段。

不推荐:

orderByDesc(updateTime);

更稳妥的方式:

orderByDesc(createTime)
.orderByAsc(id);

如果业务必须使用动态字段排序,就要接受分页不稳定是正常现象

圆球分隔图标

4 问题:分页过程中查询条件发生变化

现象

  • 第一页和第二页使用的条件不完全一致
  • 翻页后总数变化,数据错位

原因

分页本质是:同一组条件 + 不同 offset
一旦条件变化,分页语义就被破坏。

解决方案

分页过程中,必须保证:

  • 查询条件完全一致
  • 排序规则完全一致

常见做法是:前端分页参数 + 查询条件整体缓存,或由后端统一封装查询对象。

圆球分隔图标

5 问题:多表查询直接分页

现象

  • 单表分页正常,多表分页异常
  • order by 看起来没问题,结果却乱

原因

多表 join 后,数据库执行顺序可能被打乱,分页实际上作用在 join 之后的结果集 上。

解决方案

先确定主表顺序,再分页。

推荐思路:

  1. 先分页查主表 ID
  2. 再根据 ID 查关联数据
// 第一步:分页查主表
Page<Order> page = orderMapper.selectPage(page, wrapper);

// 第二步:根据 ID 查详情
List<Long> ids = page.getRecords()
                     .stream()
                     .map(Order::getId)
                     .toList();

圆球分隔图标

6 问题:分页查询和总数统计混在一起

现象

  • 总数偶尔不对
  • 分页结果和 total 对不上

原因

复杂查询下,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分页实践,是构建稳定后台服务的基本功。

开心卡通角色


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




上一篇:postmarketOS深度解析:基于Alpine Linux的轻量级Linux手机操作系统
下一篇:JavaScript面试题解析:如何让对象支持数组解构赋值 `var [a, b] = {a:1, b:2}`
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-11 18:27 , Processed in 0.235869 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表