pdo预处理语句是防止误删和sql注入的最稳妥方式,须设异常模式、全用占位符、检查rowcount()、select验证、事务控制、禁用无where删除,并优先考虑软删除。

用PDO预处理语句执行DELETE
直接拼接SQL字符串是误删和SQL注入的主因,PDO::prepare() + execute() 是目前最稳妥的路径。它把SQL结构和数据彻底分离,数据库引擎不会把参数当语法解析。
- 必须设置错误模式为异常:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION),否则错删了也静默失败 - WHERE条件里所有变量都要用占位符,哪怕只是主键ID:
DELETE FROM users WHERE id = ?或WHERE id = :id - 执行后立刻检查影响行数:
$stmt->rowCount()返回0说明没删到任何行——可能是ID不存在,也可能是条件写错 - 避免在预处理中传入表名或字段名:它们不能参数化,需白名单校验或硬编码
删除前强制用SELECT验证WHERE条件
哪怕你100%确定条件是对的,也该先跑一遍等价的SELECT。线上环境删错一条订单,比查慢200ms严重得多。
- 把DELETE语句的WHERE部分原样复制过来:
SELECT id, created_at FROM orders WHERE status = 'pending' AND updated_at - 重点看返回的行数、关键字段值是否符合预期,尤其注意NULL值是否混入(比如
NOT IN子查询里有NULL就会失效) - 大表操作建议加
LIMIT和ORDER BY,避免锁表太久;验证完再删,也建议分批删(如每次LIMIT 1000)
事务包裹+手动确认机制
DELETE本身支持事务,但很多人忘了开启。没有BEGIN,rollback就只是空谈。
- 显式开启:
$pdo->beginTransaction(),删完调commit(),出错就rollback() - 对高危操作(如按非主键条件删),可在PHP层加二次确认逻辑:比如接收一个
confirm=1参数,没带就不执行 - 生产环境严禁用
DELETE FROM table这种无WHERE的写法——即使加了事务,回滚也救不回锁导致的连接堆积 - 某些ORM会自动加事务,但别依赖它;自己控制更可靠
软删除替代硬删除的适用场景
真正需要物理删除的场景其实不多。多数业务里,“删”只是“标记为不可见”,这对审计、恢复、关联数据一致性都更友好。
- 加
is_deleted TINYINT(1) DEFAULT 0字段,删时只改这个值:UPDATE users SET is_deleted = 1 WHERE id = ? - 所有读取逻辑必须补上
AND is_deleted = 0,漏一处就数据泄露 - 索引要考虑
is_deleted字段,否则查询性能会断崖下跌 - 物理清理可安排在低峰期异步执行,且必须走单独审批流程
rowCount()就认为删成功了,或者用NOT IN时完全没意识到子查询里可能有NULL。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











