必须掌握SELECT、INSERT、UPDATE、DELETE、CREATE五类SQL语句及预处理防注入;PHP不执行SQL,仅传递给数据库解析,ORM底层仍是SQL。
PHP本身没有内置数据库操作能力,mysqli、PDO这些扩展只是“管道”,真正执行数据操作的是底层数据库(如MySQL)。你写$pdo->query("SELECT * FROM user"),实际是把字符串发给MySQL服务器去解析执行——这意味着,哪怕用ORM(如Eloquent),底层生成的仍是SQL。跳过SQL直接写CRUD,等于让别人替你写句子却不懂语法,出错时连报错信息都看不懂。
不是所有SQL都要精通,但以下五类必须手写过、调试过,不能只靠生成器或文档复制粘贴:
SELECT:带WHERE、ORDER BY、LIMIT是高频需求;JOIN在关联查询(如“查用户+对应订单”)中无法避免INSERT INTO ... VALUES:单条插入用VALUES,多条建议用INSERT INTO ... VALUES (),(),()减少IOUPDATE ... SET ... WHERE:漏写WHERE是线上事故高发原因(比如全表密码重置)DELETE FROM ... WHERE:同上,没WHERE就是清空表;软删除应优先用UPDATE设is_deleted=1
CREATE TABLE:建表语句要自己写,尤其字段类型(VARCHAR(255) vs TEXT)、索引(INDEX)、外键约束新手常把变量直接拼进SQL字符串,比如"SELECT * FROM user WHERE id = " . $_GET['id'],这等于敞开SQL注入大门。正确做法是用预处理(prepared statement):
try {
$stmt = $pdo->prepare("SELECT * FROM user WHERE status = ? AND created_at > ?");
$stmt->ex
ecute([1, '2025-01-01']);
$users = $stmt->fetchAll();
} catch (PDOException $e) {
// 注意:不要把$e->getMessage()直接输出给前端
}关键点:
?或命名参数:status由PDO自动转义,不依赖手动过滤execute()传入的数组值,类型由PDO根据字段元数据推断,不用自己castmysql_real_escape_string()(已废弃)或addslashes()替代预处理常见现象:SELECT * FROM user WHERE email = 'a@b.com'返回空,但数据明明存在。可能原因:
email VARCHAR(100) NOT NULL DEFAULT '',但实际存了NULL——WHERE email = NULL永远为false,得写WHERE email IS NULL
INT类型,但PHP传入字符串'123',MySQL会做隐式转换,但某些严格模式下会报错或不匹配utf8mb4,连接没设SET NAMES utf8mb4,中文条件查不到验证方法:在PHP里用$pdo->getAttribute(PDO::ATTR_ERRMODE)确保开启异常模式,再用echo $pdo->lastInsertId()或$stmt->rowCount()确认影响行数,比肉眼盯SQL更可靠。