必须用 pdo 或 mysqli 预处理+参数绑定操作数据库,这是起点而非进阶;直接拼接 sql 字符串极易导致 sql 注入,addslashes() 和 mysql_real_escape_string() 均不可靠;预处理分离 sql 结构与数据,占位符仅支持值绑定,类型需显式声明。

别从拼字符串写 SELECT * 开始学,那是在给自己埋 SQL 注入雷;真正要练的,是用 PDO 或 mysqli 做预处理 + 参数绑定 —— 这不是“进阶技巧”,而是 PHP 操作数据库的起点线。
为什么不能直接拼接 SQL 字符串
用户输入一进 "SELECT * FROM users WHERE name = '$name'",就等于把数据库大门钥匙塞给对方。哪怕加了 addslashes() 或 mysql_real_escape_string()(已废弃),也挡不住多字节编码绕过、宽字节注入等变种攻击。
-
mysqli_real_escape_string()只对当前连接字符集生效,SET NAMES gbk后可能失效 -
addslashes()不识别数据库协议,纯字符串替换,完全不可靠 - 前端传来的
$_GET['id']是字符串,但后端当整数用时,不校验类型就直接拼进 SQL,id=1 OR 1=1就能绕过
必须用 PDO::prepare() 绑定参数
预处理语句把 SQL 结构和数据彻底分离:SQL 模板先编译,参数在执行时单独传入。数据库引擎不会把绑定值当 SQL 解析,天然免疫注入。
- 占位符只支持
?(位置参数)或:name(命名参数),不能用于表名、字段名、排序方向等动态结构 - 绑定值类型由
PDO::PARAM_INT、PDO::PARAM_STR显式声明,避免隐式转换出错 - 批量插入用
INSERT INTO t VALUES (?, ?), (?, ?)+ 循环execute(),比逐条执行快 3–5 倍
示例:
$stmt = $pdo->prepare("SELECT id, name FROM users WHERE status = ? AND created_at > ?");
$stmt->execute([1, '2025-01-01']);
$rows = $stmt->fetchAll();
WHERE 条件里容易漏掉的边界情况
写 WHERE 不只是填等号,更要考虑空值、范围、模糊匹配和逻辑组合的真实业务约束。
-
IS NULL和= NULL效果完全不同,后者永远返回 false - 日期范围建议用
BETWEEN '2025-01-01' AND '2025-12-31 23:59:59',而不是>= '2025-01-01' AND (会丢掉当天最后一秒) -
LIKE模糊查询必须用bindValue()绑定带通配符的完整值,如$stmt->bindValue(1, "%{$keyword}%"),不能写成name LIKE '%?%' - 多个
AND/OR混用时,务必加括号明确优先级,比如(type = 1 OR type = 2) AND status = 1
性能陷阱:别让 SELECT * 拖垮应用
查 10 个字段却只用其中 2 个,不仅浪费网络带宽,还可能让索引失效、触发临时表、拖慢磁盘 I/O。
- 明确列出所需字段,例如
SELECT user_id, nickname, avatar_url,而不是SELECT * - 大文本字段(
TEXT、MEDIUMTEXT)尽量延迟加载,或单独建扩展表 -
LIMIT 1要加在确定只需一条结果的场景(如查唯一登录态),否则分页时必须配合ORDER BY+ 索引字段,否则OFFSET越大越慢 -
COUNT(*)在 InnoDB 中需扫描索引,若只要判断“是否存在”,用SELECT 1 FROM t WHERE ... LIMIT 1更轻量
真正卡住人的从来不是语法记不住,而是没想清楚“这个查询是否会被高频调用”“返回的数据会不会被前端全渲染”“条件字段有没有索引支撑”。写完一句 SQL,顺手 EXPLAIN 看一眼执行计划,比背十遍 SELECT 语法有用得多。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











