避免遗漏与重复的游标分页:设计原理
一句话总结
分页的契约不是“显示多少条”,而是在什么顺序下读到了哪里。
为什么需要它
假设你看完列表第 1 页之后,有新的条目插到了前面。这时用 offset=10 请求下一页,就可能重复看到被挤下来的条目。反过来,如果中间有删除,就可能漏掉条目。按唯一且不变的 id 排序,再读取比最后一个 id 更大的行,可以减轻这种位移问题。 但游标并不是整份数据的快照。对于已经走过的区间中后来才插入的行,它不做任何保证;而像按价格排序这样排序值会变化的列表,则需要复合键和另外的契约。
工作原理
전체 행 → 범주 필터 → id 오름차순 → id > cursor → limit + 남은 행 확인
↓
공개 필드 투영 + next_cursor
仅凭 limit=2 而结果有两条,并不能说明还有下一页。本实验只有在剩余的行数多于 limit 时,才用最后返回的 id 生成游标。在真实服务的 SQL 中,会用 WHERE id > ? ORDER BY id LIMIT (limit+1) 多读一行,做出同样的判断。这里先用一个小的内存列表来验证契约。
在现场相遇的样子
把游标转成 base64,并不等于加密或访问控制。解码之后要检查它是否是正的整数,而在真实服务中,还要决定是否把游标与过滤、排序条件绑定在一起。本实验的游标只包含 id,所以下一次请求也必须发送同样的 category。如果把内部成本之类的字段连同原始字典一起返回,即使分页是对的,数据也会泄露。把只保留公开字段的投影放在最后一步。
下一项实验要做什么
确认不规则的 id 顺序、空列表、恰好是最后一页的情形,以及非法的 limit 和游标。在最后一步中,用 TestClient 连续读取两页,检查是否有重复、遗漏和内部字段暴露。能够说明下一次请求的 category 不同,或者排序键被修改时会有什么变化,本实验才算结束。
参考:FastAPI 测试