当前位置: 首页 > news >正文

零基础PHP从零到一实现上一页和下一页的庖丁解牛

实现上一页和下一页,不是简单地用LIMIT offset, size,而是通过游标分页(Cursor-based Pagination)实现高性能、可扩展的分页。


一、核心原理:为什么不用 OFFSET?

▶ 1.OFFSET 的致命缺陷
-- 跳过 100 万行 → 扫描 1,000,010 行SELECT*FROMordersLIMIT1000000,10;
  • 问题
    • 性能随页码线性下降
    • 深度分页直接拖垮数据库
▶ 2.游标分页的优势
-- 仅扫描 10 行SELECT*FROMordersWHEREid>1000000ORDERBYidLIMIT10;
  • 优势
    • 性能恒定(O(1))
    • 适合无限滚动/深度分页

💡核心认知
“上一页/下一页” = 记录当前页首尾 ID,而非计算偏移量


二、完整实现:PHP + MySQL

▶ 1.数据库准备
-- 创建测试表CREATETABLEproducts(idINTAUTO_INCREMENTPRIMARYKEY,nameVARCHAR(255)NOTNULL,priceDECIMAL(10,2)NOTNULL);-- 插入测试数据INSERTINTOproducts(name,price)VALUES('Product 1',10.00),('Product 2',20.00),...('Product 100',1000.00);
▶ 2.PHP 分页逻辑
<?php// config.php$pdo=newPDO('mysql:host=localhost;dbname=test','user','pass');$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);// pagination.phpfunctiongetProducts($pdo,$direction='next',$cursor=null,$limit=10){if($direction==='next'){// 下一页:id > cursor$sql="SELECT * FROM products WHERE id > :cursor ORDER BY id ASC LIMIT :limit";$params=['cursor'=>$cursor??0,'limit'=>$limit];}else{// 上一页:id < cursor,按降序取,再反转$sql="SELECT * FROM products WHERE id < :cursor ORDER BY id DESC LIMIT :limit";$params=['cursor'=>$cursor,'limit'=>$limit];}$stmt=$pdo->prepare($sql);$stmt->bindValue(':cursor',$params['cursor'],PDO::PARAM_INT);$stmt->bindValue(':limit',$params['limit'],PDO::PARAM_INT);$stmt->execute();$rows=$stmt->fetchAll(PDO::FETCH_ASSOC);// 上一页结果需反转if($direction==='prev'){$rows=array_reverse($rows);}return$rows;}// 获取当前页数据$direction=$_GET['direction']??'next';$cursor=$_GET['cursor']??null;$products=getProducts($pdo,$direction,$cursor);// 提取首尾 ID$firstId=$products?$products[0]['id']:null;$lastId=$products?end($products)['id']:null;?>
▶ 3.前端 HTML
<!-- index.php --><!DOCTYPEhtml><html><head><title>产品列表</title></head><body><h1>产品列表</h1><ul><?php foreach ($products as $product): ?><li><?= htmlspecialchars($product['name']) ?>- $<?= $product['price'] ?></li><?php endforeach; ?></ul><!-- 分页按钮 --><div><?php if ($firstId): ?><ahref="?direction=prev&cursor=<?= $firstId ?>">上一页</a><?php endif; ?><?php if ($lastId): ?><ahref="?direction=next&cursor=<?= $lastId ?>">下一页</a><?php endif; ?></div></body></html>

三、关键机制解析

▶ 1.下一页逻辑
  • 参数cursor = 当前页最后一条的 id
  • 查询WHERE id > cursor ORDER BY id ASC
  • 结果:直接获取下一页 10 条
▶ 2.上一页逻辑
  • 参数cursor = 当前页第一条的 id
  • 查询WHERE id < cursor ORDER BY id DESC(倒序取)
  • 处理:PHP 中array_reverse()还原顺序
▶ 3.边界处理
  • 首页cursor = nullWHERE id > 0
  • 末页:无数据 → 隐藏“下一页”按钮

四、避坑指南

陷阱破局方案
忽略 XSS 风险输出时用htmlspecialchars()
未处理空结果检查$products是否为空
并发插入导致漏数据接受最终一致性(业务可容忍)
非自增主键确保排序字段是聚簇索引

五、终极心法

**“分页不是跳转,
而是锚点的传递——

  • 当你记录首尾 ID
    你在跳过扫描;
  • 当你反转上一页
    你在还原顺序;
  • 当你隐藏无效按钮
    你在优化体验。

真正的分页,
始于对索引的敬畏,
成于对细节的精控。”


结语

从今天起:

  1. 永远用游标分页替代 OFFSET
  2. 上一页用array_reverse()处理
  3. 输出数据必用htmlspecialchars()

因为最好的分页,
不是计算偏移,
而是精准传递每一程的锚点。

http://www.jsqmd.com/news/316807/

相关文章:

  • 2026景区游乐设备厂家选型参考:安全合规与场景融合的理性指南
  • 跳跃游戏 II | 贪心算法最优解(最少跳跃次数)
  • 深入剖析CVE-2025-20354:思科CCX系统高危RCE漏洞详解
  • AI生成测试用例的全面性优势:技术机理与实践验证
  • 我让AI读了1000个测试用例,总结出“好用例”的5个特征
  • 写论文软件哪个好?实测 10 款工具后,虎贲等考 AI 凭 “全流程闭环” 稳赢
  • 10个技巧:用AI自动生成测试报告
  • 【收藏必学】大模型技术全解析:从入门到实践的人工智能核心指南
  • 2026可靠伦茨减速机优质厂家推荐榜:伦茨制动器、伦茨变频器、伦茨控制器、伦茨直流调速器、伦茨维修、伦茨驱动器选择指南
  • 常州市英语雅思培训机构推荐,2026权威测评出国雅思辅导机构口碑榜单.
  • 终极预测:2030年,AI将自动编写测试用例?
  • 实时AI监控测试实战:从理论到落地的全面指南
  • AI创作避坑 学术党实测有效,免费搞定查重+绘图+改稿
  • 震惊!这3个VS Code插件让调试快如闪电:软件测试从业者的效率革命
  • 2026年趋势:开发者必学的联邦学习测试
  • 硬盘数据损坏分析
  • 9999999
  • 打造半导体行业培训新视野:3D动画助力固晶机应用解析
  • 【图像加密】基于 DCT 变换的图像加密与解密附matlab代码
  • 收藏必看!告别RAG碎片化:一文讲透Forms-Dynamics框架下的Agent记忆系统
  • 收藏!2026年AI行业最大机会,锁定应用层赛道
  • 收藏!Java程序员转行大模型开发:从入门到落地的完整指南
  • 何洁月 C++教程 初学者编程入门视频讲解
  • 管理信息系统第一次作业指南与在线完成技巧
  • 华师在线作业系统2026使用指南:功能详解与高效提交技巧
  • 零基础C语言教程视频推荐,哪个好?
  • 2026Deepseek 知识库部署服务实力榜单:经验丰富的专业实施服务商推荐
  • 2026年全国设备搬运公司哪家强?多家厂家优势对比 特色服务拆解
  • Flutter艺术探索-MethodChannel原理:Flutter与原生通信机制
  • 一站式BI私有化部署服务提供商推荐2026 本地部署厂商与智能BI方案商全收录