php查询数据库的核心在于选对扩展(mysqli或pdo)、传准参数、严防sql注入;需检查连接状态、查询错误及结果集是否为空,中文字符须统一utf8mb4编码,where条件必须预处理,大数据量应流式fetch避免内存溢出。

PHP 查询数据库数据,核心不是写 SELECT 语句本身,而是用对扩展、传对参数、防好注入——否则哪怕 SQL 写得再标准,也可能查不到数据、报错、甚至被拖库。
用 mysqli 还是 PDO?选哪个更稳妥
两者都能执行 SELECT,但行为差异直接影响结果可靠性:
-
mysqli更轻量,适合只用 MySQL 的项目;但默认开启“缓存结果集”,mysqli_query()返回的是资源(resource),不显式mysqli_free_result()可能内存泄漏 -
PDO支持预处理和多种数据库,PDO::prepare()+PDOStatement::execute()是防 SQL 注入的标配;注意它默认不抛异常,要手动设PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION - 如果查询含中文或特殊字符,
PDO必须在 DSN 中加;charset=utf8mb4,mysqli则需调用mysqli_set_charset($conn, 'utf8mb4'),漏掉就可能返回空数组或乱码
SELECT 查不到数据?先检查这三件事
常见现象:SQL 在 phpMyAdmin 里能跑,PHP 里 mysqli_fetch_assoc() 却返回 null 或空数组。
- 确认连接成功:
mysqli_connect()或new PDO()后立刻检查是否为 false / 是否捕获到异常,别跳过这步 - 确认查询没报错:用
mysqli_error($conn)或$pdo->errorInfo()看真实错误,比如字段名拼错、表不存在、权限不足都会静默失败 - 确认结果集非空:不要直接对
mysqli_query()返回值调fetch,先用mysqli_num_rows()或$stmt->rowCount()判断是否有行,再取数据
WHERE 条件带变量?必须用预处理,别拼字符串
手拼 "SELECT * FROM user WHERE id = " . $_GET['id'] 是高危操作,整数也防不住绕过(如传 1 OR 1=1)。
-
PDO示例:$stmt = $pdo->prepare("SELECT * FROM user WHERE status = ? AND created_at > ?"); $stmt->execute(['active', '2024-01-01']); $rows = $stmt->fetchAll(); -
mysqli示例:$stmt = mysqli_prepare($conn, "SELECT * FROM user WHERE name LIKE ?"); $search = "%{$keyword}%"; mysqli_stmt_bind_param($stmt, "s", $search); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); - 注意:
LIKE中的通配符(%、_)必须放在 PHP 变量里拼好,不能写进 SQL 模板,否则预处理会把%当字面量处理
查大量数据时,fetch_all() 和循环 fetch() 性能差很多
一次性 fetch_all(MYSQLI_ASSOC) 看似方便,但万级记录会吃光内存;而逐行 fetch_assoc() 虽慢点,却可控。
- 导出报表、后台批量处理等场景,优先用
while ($row = $result->fetch_assoc()) { ... }流式读取 - 如果真要用
fetch_all(),记得限制条数:SELECT * FROM log ORDER BY id DESC LIMIT 1000,别裸查全表 -
PDO的fetch()默认是PDO::FETCH_BOTH,既返回数字键又返回字段名键,占双倍内存;明确指定PDO::FETCH_ASSOC
最常被忽略的一点:查询前没确认字符集是否一致,尤其当数据库用 utf8mb4 而 PHP 连接用 latin1 时,WHERE name = '张三' 会永远匹配不上——这个坑不会报错,只会让你对着空数组发呆十分钟。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











