

新闻资讯
技术教程DELETE语句必须带WHERE条件,否则会清空整张表;应先用SELECT验证、用预处理防注入、用事务保证一致性、优先软删除而非硬删除。
不加 WHERE 的 DELETE FROM users; 会清空整张表,不是删错一条,是删光所有数据。初学者常在测试环境随手写 DELETE FROM log; 就回车,结果发现日志全没了。
实操建议:
DELETE 语句,先改成 SELECT * 跑一遍
WHERE id = ? 或 WHERE status = 'draft' 这类明确、可预判的条件,避免用 WHERE name LIKE '%abc%' 这类易误伤的模糊条件"DELETE FROM users WHERE id = " . $_GET['id'] —— 这种写法一旦 $_GET['id'] 是 1 OR 1=1,就变全表删除手动拼接 $_POST 或 $_GET 到 SQL 里,等于给 SQL 注入大开绿灯。哪怕只是删自己账号,攻击者也能通过修改请求参数删掉管理员记录。
正确做法是用 PDO 预处理绑定参数:
try {
$pdo = new PDO($dsn, $user, $pass);
$stmt = $pdo->prepare("DELETE FROM users WHERE id = :id AND status = 'inactive'");
$stmt->execute(['id' => (int)$_POST['user_id']]);
} catch (PDOException $e) {
error_log('Delete failed: ' . $e->getMessage());
}
注意点:
:id 占位符比 ? 更清晰,尤其多参数时;但无论哪种,都必须调用 execute() 传值,不能直接把变量塞进 SQL 字符串(int) 强转能防基础注入,但不能替代预处理——比如删文章时按标题删,title 是字符串,就必须用 :title 绑定,不能靠强转$stmt->rowCount() 返回值,如果是 0,说明没删到数据,可能是 ID 不存在或条件不匹配,别默认“删成功了”删数据常伴随关联操作:比如删用户,要同步删其订单、评论、头像文件。中间任何一步失败(如磁盘满导致文件删不了),数据库却已提交了用户记录,就会出现数据不一致。
必须用事务兜底:
$pdo->beginTransaction();
try {
$pdo->exec("DELETE FROM users WHERE id = 123");
$pdo->exec("DELETE FROM orders WHERE user_id = 123");
unlink('/uploads/avatar_123.jpg');
$pdo->commit();
} catch (Exception $e) {
$pdo->rollback();
throw $e;
}
关键提醒:
InnoDB(用 SHOW CREATE TABLE users; 查)unlink() 这类 PHP 文件操作无法回滚,得放在事务 之后,或改用软删除(把 status 改为 deleted)来规避真实业务中,“删”往往只是“用户不想再看到”,而不是“数据彻底无价值”。硬删除后审计、恢复、统计都成问题,还容易因外键约束失败报错。
推荐用软删除字段:
deleted_at 字段(DATETIME NULL),删时只更新它:UPDATE users SET deleted_at = NOW() WHERE id = ?
WHERE deleted_at IS NULL,可用视图或 ORM 范围作用域统一处理DELETE FROM users WHERE deleted_at ,并确保有备份
注意:软删除会让索引效率略降,高频读写的表需评估;另外,COUNT(*) 和分页逻辑要重写,不然会把已删数据也算进去。