直接改offset会导致增量更新失效,因新数据插入会改变原页偏移位置,造成漏数或重复;应改用基于ID或时间戳的游标分页,通过WHERE id > ?等范围查询实现真增量。

为什么直接改 offset 会导致增量更新失效
PHP 分页常用 LIMIT offset, length,但“增量更新”不是指翻页时多查几条,而是指:新数据插入后,用户在第2页浏览时,下拉刷新或点击“加载更多”应只拿到新增的那几条,而不是重新拉整页。问题出在 offset 是基于当前总记录数计算的——一旦有新记录插入(尤其在第1页之前),原第2页的 offset 就会错位,导致漏掉或重复。
用时间戳/ID游标替代 offset 实现真增量
核心思路是放弃“第几页”的概念,改用“从某条记录之后继续取”。前提是数据有单调递增字段(如 id 或 created_at)且已建立索引。
- 首次请求传空游标:
GET /api/items?limit=20→ 返回最后一条的id(比如105) - 下一页请求带游标:
GET /api/items?cursor=105&limit=20 - SQL 改为:
SELECT * FROM items WHERE id > ? ORDER BY id ASC LIMIT ?(注意不能用>=,否则可能重复) - 若用时间戳,需处理秒级重复:加
AND (created_at, id) > (?, ?)复合条件
mysqli 和 PDO 中游标分页的参数绑定差异
两种扩展对复合游标(如时间戳+ID)的绑定方式不同,容易报错:
-
mysqli需显式拼接类型:$stmt->bind_param('si', $timestamp, $id)—— 注意顺序和类型字符必须匹配 -
PDO用命名占位符更安全:$stmt->execute([':ts' => $timestamp, ':id' => $id]),但 WHERE 子句得写成WHERE (created_at, id) > (:ts, :id) - MySQL 8.0+ 支持行构造器比较,低版本需改写为
created_at > ? OR (created_at = ? AND id > ?)
前端如何配合避免“假加载”和状态错乱
后端游标生效,前端没同步也会白搭。常见坑:
立即学习“PHP免费学习笔记(深入)”;
- 不缓存上一页的游标值,每次“加载更多”都用初始游标,结果永远是第二页
- 用户快速滚动触发多次请求,未取消前序请求,导致后返回的数据覆盖先返回的,UI 出现跳变
- 新增数据后未重置游标链,比如发了新帖,但“最新”Tab 还在用旧游标,就看不到自己刚发的内容
- 建议:把游标存在组件 state 里;用
AbortController控制并发;新增操作后清空当前列表并重置游标为空
游标分页本身不难,难的是前后端对“游标生命周期”的认知一致——它不是一次性的 token,而是当前数据视图的快照锚点。漏掉任意一环,增量就会退化成全量 reload。



















