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

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

游标本身就是一条数据的唯一标识(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 小时前
快速集群安装mysql
数据库·mysql
北风toto6 小时前
通过Entity 创建数据库中的表,目前只支持mysql,A.CTable使用mybatis/mybatis-plus自动创建表
数据库·mysql·mybatis
念恒123068 小时前
MySQL表的约束(上)
数据库·mysql
海市公约8 小时前
MySQL核心概念及SQL语句与数据类型详解
mysql·sql语句·数据类型·运算符·ddl·dml·数据库入门
x***r1518 小时前
heidisql数据库客户端使用步骤详解(附HeidiSQL连接MySQL与SQL执行教程)
数据库·sql·mysql
Nontee9 小时前
如何用 MySQL 实现一个可重入的锁?
数据库·mysql
坚定学代码9 小时前
如何在c++中使用MySQL
开发语言·c++·mysql
浪客灿心11 小时前
MySQL的内置函数和复合查询
mysql
罗超驿12 小时前
21.jdbc 学习笔记:从原理到实践的全流程梳理
java·数据库·mysql·面试