逻辑删除是通过 status 字段标记删除状态而非物理删除,所有查询必须加 status = 1 过滤,UPDATE 替代 DELETE,建议用 TINYINT(1) 或 ENUM 类型并加索引,需记录 deleted_at 并校验恢复操作。
直接删掉数据库记录是物理删除,风险高、不可逆;逻辑删除只是把 status 字段设为已删除状态(比如 0 或 'deleted'),后续查询时过滤掉这些记录。这是 PHP 项目里最常用、也最稳妥的软删除方案。
一旦用了逻辑删除,所有读取数据的 SQL 都得默认排除已标记删除的行,否则用户会看到“不该看到的数据”。漏加 WHERE status = 1 是最常见、也最危险的疏忽。
status = 1
id 做唯一判断——攻击者可能传一个 status = 0 的 ID,后端没校验就返回数据SELECT id, title FROM articles WHERE status = 1 AND id = ?
原来写 DELETE FROM users WHERE id = ? 的地方,现在统一改成 UPDATE 更新状态字段。注意:不要用 INSERT ... ON DUPLICATE KEY UPDATE 或触发器模拟删除,那会增加复杂度和出错概率。
TINYINT(1)(值 0/1)或 ENUM('active','deleted'),避免用字符串如 'disabled' 增加拼写错误风险status 字段加索引,尤其当表数据量大、又频繁按状态筛选时UPDATE orders SET status = 0, deleted_at = NOW() WHERE id = ? AND status = 1
逻辑删除不是加个字段就完事,很多坑藏在边界里:
deleted_at 字段建议一并记录,用于审计或后期清理,且能辅助判断“是否真删过”UPDATE ..
. SET status = 1,但必须校验原记录确实存在且当前是已删除态状态字段本身不难,难的是整个系统所有数据流都对它保持一致认知——哪怕一个接口忘了加 status = 1,就等于逻辑删除形同虚设。