游标分页 + 数据删除:游标被删的完整解决方案

游标分页 + 数据删除:游标被删的完整解决方案

游标本身就是一条数据的唯一标识(ID / 时间戳),如果这条数据被物理删除了,游标就会失效。

完全有成熟、简单的解决方案,不用怕删除导致分页崩掉。

一、先搞懂:游标分页的核心原理

游标分页不是靠 page=1&size=10 跳页,而是靠:

给我上一页最后一条数据的唯一标识(游标),查询比它更早 / 更新的数据。

举个例子:

  • 消息列表:id=100,99,98...1
  • 第一页游标:cursor=100
  • 下一页:查 id < 100 的数据

游标 = 上一页最后一条数据的 ID

二、删除游标数据会发生什么?

场景复现

  1. 你加载完一页,游标停在 id=95(这条消息是用户自己发的)
  2. 用户立刻删除了 id=95 这条消息
  3. 你滑动加载下一页,请求带上 cursor=95

结果

  1. 数据库查不到 cursor=95 这条数据
  2. 分页逻辑直接卡住 / 报错 / 查不出下一页
  3. 前端表现:加载下一页转圈圈,没数据

这就是你担心的游标被物理删除导致分页失效

三、企业级通用解决方案:不要物理删除!

这是解决游标分页 + 删除问题的唯一标准方案

改用【软删除】,不物理删除

  • 不执行 DELETE FROM msg WHERE id=95
  • 执行 UPDATE msg SET is_deleted = 1 WHERE id=95

为什么这样能解决问题?

  1. 游标数据还在数据库里

    • 虽然用户看不见,但 id=95 这条记录还存在
    • 游标查询不会报错、不会断链
  2. 查询时自动过滤已删除数据查询时自动过滤已删除数据

mysql 复制代码
-- 游标分页正常查询,过滤删除数据
SELECT * FROM message
WHERE is_deleted = 0  -- 关键!只查未删除
  AND id < #{cursor}
ORDER BY id DESC
LIMIT 20

完美效果

  • 用户删除消息:前端消失、数据库保留标记
  • 游标依然有效,分页完全不受影响
  • 不会漏数据、不会重复、不会断页

这就是聊天、评论、信息流场景 100% 用的方案。

四、极端情况:必须物理删除,怎么办?

如果你项目强制物理删除(不推荐),也有兜底方案:

方案 1:游标不依赖最后一条数据,用【范围游标】

不用单条 ID 做游标,改用时间 / ID 区间

  • 游标:max_id=100, min_id=80
  • 下一页:id < 80
  • 就算中间删数据,不影响分页

方案 2:查询时判断游标是否存在,不存在就自动修复

后端逻辑:

  1. 接收前端传来的 cursor
  2. 先查该数据是否存在
  3. 不存在就找离它最近的有效数据作为新游标
  4. 继续分页

伪代码:

js 复制代码
let cursor = req.query.cursor;
// 检查游标是否存在
const exist = await db.find({ id: cursor });
if (!exist) {
  // 自动找最近的有效数据作为新游标
  cursor = await db.findOne({
    where: { id < cursor, is_deleted:0 },
    order: { id: 'desc' }
  }).id;
}
// 正常分页查询

五、总结:游标分页+删除的最佳实践

问题 解决方案 效果
游标数据被物理删除 禁止物理删除 分页失效
游标数据被软删除 is_deleted 标记 分页完全正常
必须物理删除 自动修复游标 兼容但复杂

最终结论

  1. 用户删除消息,一定会导致游标对应数据消失
  2. 软删除(is_deleted)是唯一简单、稳定、通用的解法
  3. 聊天、消息流场景必须用软删除,否则分页一定会出问题
相关推荐
南墙上的石头5 小时前
麒麟 V10 重装人大金仓 V8R6 踩坑实录(含 MySQL 兼容模式)
数据库·mysql
执子手 吹散苍茫茫烟波8 小时前
RC 隔离级别下 MySQL InnoDB 死锁典型案例
数据库·mysql
峥无11 小时前
深入理解MySQL事务与MVCC机制
数据库·mysql
要开心吖ZSH14 小时前
MVCC 进阶:快照读 vs 当前读、幻读与 Next-Key Lock
java·数据库·sql·mysql·mvcc
万亿少女的梦16815 小时前
基于Spring Boot的天空影院电影网站系统设计与实现
java·spring boot·mysql·vue·系统设计
万亿少女的梦16815 小时前
基于Spring Boot的社区管理系统设计与实现
java·spring boot·mysql·vue·系统设计
翔云12345615 小时前
简单概括主库上 Executed_Gtid_Set 是什么时候更新的
数据库·mysql
要开心吖ZSH15 小时前
Java事务与MySQL事务的关系及MVCC通俗解析
java·开发语言·mysql·mvcc
爱喝热水的呀哈喽16 小时前
hypermesh两个网格参数解析
服务器·数据库·mysql
万亿少女的梦16816 小时前
基于Spring Boot的楚雄旅游景区门票售卖系统设计与实现
java·spring boot·mysql·vue·系统设计