PHP分页怎么连接数据库?PHP数据库查询分页操作方法详解

来源:NoSQL教程作者:深圳网站建设头衔:草根站长
导读:本期聚焦于深圳网站建设创作的《PHP分页怎么连接数据库?PHP数据库查询分页操作方法详解》,敬请观看详情。数据量一上来,一次性把整张表的数据全部查出来再展示,页面必然卡顿甚至超时,这时候分页就成了必须掌握的技能。本文围绕PHP连接MySQL数据库并实现分页查询展开,先讲解mysqli和PDO两种连接方式的基本写法,再分析LIMIT加OFFSET组合实现分页的SQL原理,然后给出一个完整可运行的分页代码示例,包括页码计算、偏移量处理、总记录数统计以及分页导航条的生成。文中还提到了大数据量下OFFSET过深带来的性能隐患和优化思路,帮助你在实际项目中写出既正确又高效的分页功能。

做后台管理系统或者列表页的时候,分页几乎是绕不开的功能。用户要看的可能只是第3页的10条数据,如果你把几万条记录全部查出来交给前端处理,不仅浪费带宽,数据库的压力也会非常大。本文就从PHP连接MySQL讲起,一步步实现一个完整的分页查询功能,把页码计算、SQL拼接、导航条生成这些细节都说清楚。

PHP分页怎么连接数据库?PHP数据库查询分页操作方法详解

一、PHP连接MySQL数据库的两种常用方式

在PHP里操作MySQL,主流的有两种方式:mysqli扩展和PDO。mysqli是MySQL专用的扩展,提供面向对象和面向过程两种写法,上手简单;PDO则是PHP官方推荐的数据库抽象层,支持多种数据库,写法统一,并且天然支持预处理语句,防注入能力更强。

先看mysqli的面向对象写法,注意数据库名、用户名和密码要换成自己的:

<?php
// mysqli 面向对象方式连接
$conn = new mysqli('127.0.0.1', 'root', '123456', 'test');
if ($conn->connect_error) {
    die('连接失败: ' . $conn->connect_error);
}
$conn->set_charset('utf8mb4'); // 设置字符集,避免中文乱码
?>

再看PDO的写法,PDO需要通过DSN字符串来指定数据库类型和地址:

<?php
// PDO方式连接
try {
    $pdo = new PDO('mysql:host=127.0.0.1;dbname=test;charset=utf8mb4', 'root', '123456');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 开启异常模式
} catch (PDOException $e) {
    die('连接失败: ' . $e->getMessage());
}
?>

两种方式各有侧重。小项目或者只用MySQL的场景,mysqli足够了;如果考虑以后可能换数据库,或者团队规范要求统一使用预处理语句,那就选PDO。分页的核心逻辑与连接方式无关,后面的示例为了通用性,会用PDO来演示。

二、分页的核心原理:LIMIT与页码计算

分页的本质,就是在SQL里用LIMIT限制每次取出的条数,用OFFSET指定从第几条开始取。假设每页显示10条,第1页取第1到10条,第2页取第11到20条,以此类推。换算成SQL就是:

SELECT * FROM articles ORDER BY id DESC LIMIT 10 OFFSET 0;   -- 第1页
SELECT * FROM articles ORDER BY id DESC LIMIT 10 OFFSET 10;  -- 第2页
SELECT * FROM articles ORDER BY id DESC LIMIT 10 OFFSET 20;  -- 第3页

由此可以推导出核心公式:偏移量 = (当前页码 - 1) × 每页条数。当前页码一般通过URL参数传递,比如list.php?page=2,用$_GET['page']获取。这里有个很容易踩的坑:用户可能手动输入page=0page=-5甚至page=abc,如果不做校验,轻则查出空结果,重则SQL报错。所以拿到页码后必须做强制转换和范围校验:

<?php
$page = isset($_GET['page']) ? intval($_GET['page']) : 1; // 强制转整数
$page = max($page, 1); // 最小为1

$pageSize = 10; // 每页条数
$offset = ($page - 1) * $pageSize;
?>

另一个必须处理的细节是总页数的计算。总页数等于总记录数除以每页条数再向上取整,比如103条数据、每页10条,结果是10.3,需要显示11页。PHP里用ceil()函数就能搞定。而总记录数需要额外执行一次COUNT(*)查询,千万别用count(查询结果数组)来统计,那样等于把全表数据都取了一遍,分页就失去意义了。

三、完整的分页实现代码

把前面的知识点串起来,下面是一个可以直接运行的完整示例,包含取页码、算偏移、查总数、取当前页数据、生成导航条五个步骤:

<?php
$pdo = new PDO('mysql:host=127.0.0.1;dbname=test;charset=utf8mb4', 'root', '123456');

// 1. 获取并校验页码
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$page = max($page, 1);
$pageSize = 10;

// 2. 查询总记录数
$total = $pdo->query('SELECT COUNT(*) FROM articles')->fetchColumn();
$totalPages = ceil($total / $pageSize);

// 3. 页码超出范围时纠正到最后一页
if ($page > $totalPages && $totalPages > 0) {
    $page = $totalPages;
}
$offset = ($page - 1) * $pageSize;

// 4. 用预处理语句查询当前页数据
$stmt = $pdo->prepare('SELECT id, title, created_at FROM articles ORDER BY id DESC LIMIT :limit OFFSET :offset');
$stmt->bindValue(':limit', $pageSize, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$list = $stmt->fetchAll(PDO::FETCH_ASSOC);

// 5. 输出数据和分页导航
foreach ($list as $row) {
    echo '<div>' . htmlspecialchars($row['title']) . '</div>';
}

echo '<div class="pager">';
if ($page > 1) {
    echo '<a href="?page=' . ($page - 1) . '">上一页</a> ';
}
for ($i = 1; $i <= $totalPages; $i++) {
    $style = ($i == $page) ? 'font-weight:bold' : '';
    echo "<a href=\"?page=$i\" style=\"$style\">$i</a> ";
}
if ($page < $totalPages) {
    echo '<a href="?page=' . ($page + 1) . '">下一页</a>';
}
echo '</div>';
?>

这段代码有几个值得注意的地方。LIMIT和OFFSET用了bindValue并显式指定PDO::PARAM_INT,因为PDO默认会把参数当成字符串拼接,写成LIMIT '10'会导致SQL语法错误。输出标题时用了htmlspecialchars转义,防止存储在数据库里的内容被当成HTML执行,造成XSS漏洞。

分页导航条这里为了演示只做了最简单的全部页码输出,数据量大的列表页通常会做成「上一页 1 2 3 ... 9 10 下一页」这种带省略号的样式,思路是计算当前页附近的页码区间,首尾页固定显示,中间用省略号占位,逻辑稍微复杂一点但原理相同。

四、深分页的性能问题与优化思路

上面这套写法在中小数据量下完全够用,但当数据达到百万级,问题就会暴露出来:LIMIT 10 OFFSET 999990这种深分页查询,MySQL实际要取出前100万条记录再丢弃,页码越靠后越慢。很多人以为LIMIT本身是优化手段,其实OFFSET越大,扫描的行数越多,这是个常见的误区。

优化方案常见的有两种。第一种是子查询定位法,先用覆盖索引定位到起始id,再回表取数据:

SELECT * FROM articles
WHERE id <= (
    SELECT id FROM articles ORDER BY id DESC LIMIT 999990, 1
)
ORDER BY id DESC LIMIT 10;

内层子查询只走主键索引,速度非常快;外层根据定位到的id直接取后续10条,避免了大量无效回表。第二种是游标分页,也就是不传页码,改传上一页最后一条记录的id,SQL写成WHERE id < :lastId ORDER BY id DESC LIMIT 10。这种方式每次都从索引定位点开始扫描,性能与页码深度无关,特别适合App里的下拉加载更多场景,缺点是没法直接跳转到指定页,需要根据业务权衡。

总结一下,PHP做数据库分页的完整链路是:连接数据库、校验页码、算偏移量、COUNT统计总数、LIMIT取数据、生成导航条。把这六步的逻辑理清楚,再结合预处理语句防注入、htmlspecialchars防XSS,一个既安全又好用的分页功能就成型了。数据量上来之后再考虑深分页优化,循序渐进即可。

PHP分页数据库查询分页类修改时间:2026-09-11 12:08:43

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260911/54658.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。