mysql实现游标分页的方法详解

 更新时间:2025年10月14日 09:08:45   作者:惊鸿一博  
这篇文章主要为大家详细介绍了mysql实现游标分页的相关方法,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下

这是一种基于排序字段值而不是偏移量的分页方法。

核心思想

记住上一页最后一条记录的位置,然后从这个位置开始查询下一页

逐步分解

第一页查询(基础查询)

SELECT * FROM loc_common_info 
WHERE id NOT IN (1,2,3)  -- 假设用户去过场地1,2,3
AND status = 'ACTIVE'
ORDER BY popularity_score DESC, id DESC
LIMIT 3;  -- 假设每页3条

假设返回结果:

idnamepopularity_score
10场地A95
8场地B95
5场地C90

关键点:我们记录最后一条记录的值:

  • lastScore = 90 (id=5的popularity_score)
  • lastId = 5 (最后一条记录的id)

第二页查询(使用游标)

SELECT * FROM loc_common_info 
WHERE id NOT IN (1,2,3) 
AND status = 'ACTIVE'
-- 关键条件:找到排在"最后一条记录"之后的所有记录
AND (popularity_score < #{lastScore} 
     OR (popularity_score = #{lastScore} AND id < #{lastId}))
ORDER BY popularity_score DESC, id DESC
LIMIT 3;

条件逻辑详解

条件分解

AND (
    popularity_score < 90 
    OR 
    (popularity_score = 90 AND id < 5)
)

这个条件的意思是:

popularity_score < 90

  • 找到所有评分严格小于90的记录
  • 这些记录自然排在评分90的记录后面

popularity_score = 90 AND id < 5

  • 找到评分等于90,但id更小的记录
  • 因为排序是 popularity_score DESC, id DESC,所以id小的排在后面

实际数据示例

假设数据库中有这些数据:

idpopularity_score
1095
895
590
390
785
285
480

第二页查询条件(score < 90) OR (score = 90 AND id < 5)

符合条件的记录:

  • id=3:满足 score = 90 AND id < 5
  • id=7:满足 score < 90
  • id=2:满足 score < 90
  • id=4:满足 score < 90

排序后第二页结果:

idpopularity_score
390
785
285

为什么需要复合排序ORDER BY score DESC, id DESC

如果只按 popularity_score DESC 排序:

问题场景:多个记录有相同的popularity_score

第一页:id=10(95), id=8(95), id=5(90)  ← 最后一条id=5, score=90
第二页应该显示:id=3(90), id=7(85), id=2(85)

但如果只按score排序,数据库不保证相同score的记录顺序稳定,可能导致:

  • 第一次查询:id=10(95), id=8(95), id=5(90)
  • 第二次查询:id=10(95), id=8(95), id=3(90) ← 顺序变了!

复合排序确保:

  • 主要按popularity_score降序
  • score相同时,按id降序,保证顺序绝对稳定

前端-后端交互流程

// 第一页请求
PageRequest request1 = new PageRequest(0, 3, null); // 没有游标
PageResult result1 = service.getRecommendations(request1);

// 返回结果包含下一页游标
String nextCursor = result1.getNextCursor(); // 编码为: "90_5"

// 第二页请求
PageRequest request2 = new PageRequest(0, 3, "90_5"); // 使用游标
PageResult result2 = service.getRecommendations(request2);

与传统OFFSET分页对比

OFFSET分页(有问题)

-- 第一页
SELECT ... LIMIT 0, 3;  -- 返回记录1,2,3

-- 第二页  
SELECT ... LIMIT 3, 3;  -- 返回记录4,5,6

问题:如果第一页和第二页之间有新数据插入,会导致:

  • 重复记录(新数据挤占了位置)
  • 丢失记录(原有记录被挤到后面)

游标分页(稳定)

-- 第一页:返回id=10,8,5,记住lastScore=90, lastId=5
-- 第二页:查询score<90 OR (score=90 AND id<5)的记录

优势

  • 不受数据增删影响
  • 性能更好(不需要计算OFFSET)
  • 顺序绝对稳定

总结

游标分页的核心就是:记住上一页的终点,从终点开始找下一页,通过复合排序和精确的条件定位,确保分页的准确性和稳定性。

游标对象设计

@Data
public class RecommendationCursor {
    private String type;        // "new", "rotate", "retain"
    private Double lastScore;   // 上一页最后一条的popularity_score
    private Long lastId;        // 上一页最后一条的ID
    private Integer page;       // 当前页码
    private String randomSeed;  // 随机种子
    
    public static RecommendationCursor parseCursor(String cursorStr, String type) {
        if (cursorStr == null) {
            return new RecommendationCursor(type, null, null, 0, generateRandomSeed());
        }
        // 解析游标逻辑...
    }
    
    public String toCursorString() {
        // 生成游标字符串逻辑...
    }
}

关键要点

  • 不要使用 OFFSET:LIMIT offset, count 在数据量大时性能差且不稳定
  • 游标分页:适合主内容区,保证稳定性和性能
  • 随机分页:适合轮换区,增加多样性
  • 复合排序:ORDER BY score DESC, id DESC 确保排序稳定
  • 状态保持:通过游标或种子保持分页状态

这样设计后,每次分页查询都能返回不同的内容,同时保证性能和稳定性。

到此这篇关于mysql实现游标分页的方法详解的文章就介绍到这了,更多相关mysql游标分页内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • mysql 触发器用法实例详解

    mysql 触发器用法实例详解

    这篇文章主要介绍了mysql 触发器用法实例详解的相关资料,需要的朋友可以参考下
    2017-06-06
  • MySQL 使用触发器记录用户的操作日志问题

    MySQL 使用触发器记录用户的操作日志问题

    使用 MySQL 触发器可以记录哪些用户、什么时间对数据表进行了增、删、改操作。如果执行删除操作,则记录删除之前的数据记录;如果执行更新操作,记录更新之前的数据记录,这篇文章主要介绍了MySQL 使用触发器记录用户的操作日志,需要的朋友可以参考下
    2022-12-12
  • mysql事务处理用法与实例代码详解

    mysql事务处理用法与实例代码详解

    这篇文章主要介绍了mysql事务处理用法与实例代码详解,详细的介绍了事物的特性和用法并实现php和mysql事务处理例子,非常具有实用价值,需要的朋友可以参考下
    2018-12-12
  • MySQL事务与隔离级别的使用基础理论

    MySQL事务与隔离级别的使用基础理论

    这篇文章主要介绍了MySQL事务的隔离级别详情,事务隔离级别越高,为避免冲突所花费的性能也就越多,即效率低。在“可重复读”级别,实际上可以解决部分的虚读问题,但是不能防止update更新产生的虚读问题,要禁止虚读产生,还是需要设置串行化隔离级别
    2023-02-02
  • 浅谈开启magic_quote_gpc后的sql注入攻击与防范

    浅谈开启magic_quote_gpc后的sql注入攻击与防范

    通过启用php.ini配置文件中的相关选项,就可以将大部分想利用SQL注入漏洞的骇客拒绝于门外
    2012-01-01
  • 解决ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (111)的问题

    解决ERROR 2003 (HY000): Can‘t connect to MySQL server 

    在Windows系统上使用Django连接Ubuntu虚拟机中的MySQL数据库时,遇到无法连接的问题,排查后发现是由于MySQL绑定的IP地址改变导致的,下面就来介绍一下问题解决,感兴趣的可以了解一下
    2024-09-09
  • MySQL下高可用故障转移方案MHA的超级部署教程

    MySQL下高可用故障转移方案MHA的超级部署教程

    这篇文章主要介绍了MySQL下高可用故障切换方案MHA的超级部署教程,文中队MHA方案的一些特点做了介绍,示例基于Linux系统的服务器环境,需要的朋友可以参考下
    2015-12-12
  • mysql中的int(10)int(20)分别代表什么意思

    mysql中的int(10)int(20)分别代表什么意思

    这篇文章主要介绍了mysql中的int(10)int(20)分别代表什么意思,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • MySQL与MSSQl使用While语句循环生成测试数据的代码

    MySQL与MSSQl使用While语句循环生成测试数据的代码

    有时候我们测试性能的时候经常需要生产大量的测试数据,用sql语句直接生成的数据更快,需要的朋友可以参考下。
    2010-12-12
  • MySQL 连接查询的原理和应用

    MySQL 连接查询的原理和应用

    这篇文章主要介绍了MySQL 连接查询的原理和应用,帮助大家更好的理解和学习MySQL数据库,感兴趣的朋友可以了解下
    2020-11-11

最新评论