softdeletebehavior是yii2最稳妥的软删除实现方式,需正确配置softdeleteattributevalues、replaceregulardelete和restoreattributevalues参数,并在所有查询中显式过滤软删除字段,避免漏查或误删。

SoftDeleteBehavior 是 Yii2 实现软删除最稳妥的方式,但直接改 delete() 行为或手写 update() 容易漏掉查询过滤、恢复逻辑和批量操作支持。
软删除字段怎么选:isDeleted 还是 deletedAt?
两种都行,但语义和后续扩展性差别明显:
-
isDeleted(布尔型):简单直观,适合只需要“删/不删”二元状态的场景;查询快,索引友好;但无法知道何时删的,审计困难 -
deletedAt(datetime/timestamp):记录精确时间,方便做软删除后 30 天自动清理、恢复窗口限制等;但查询时得用IS NOT NULL,MySQL 对NULL字段索引效率略低 - 别用
deleteFlag这类模糊命名,容易和业务字段冲突;也别用整数0/1/9,语义不清且后期难扩展
SoftDeleteBehavior 配置里最关键的三个参数
行为配置不是填完就完事,这几个键值直接影响是否生效、能否恢复、会不会误删:
-
'softDeleteAttributeValues' => ['isDeleted' => true]:必须和数据库字段类型一致;如果字段是TINYINT(1),这里写true没问题(Yii 会转成1),但写'1'字符串可能在某些驱动下出错 -
'replaceRegularDelete' => true:启用后,调$model->delete()就走软删;但要注意——控制器里若还保留$model->delete()调用,它就不再触发beforeDelete事件,原有逻辑会失效 -
'restoreAttributeValues' => ['isDeleted' => false]:显式声明恢复值;不设这个,restore()默认只清空deletedAt或设isDeleted为false,但如果你用的是status字段值为2表示已删除,那必须配清楚
查询时漏加软删除条件,数据就「漏」出来了
行为本身不改查询逻辑,所有 find() 默认查全部记录。必须主动过滤:
- 查正常数据:
Item::find()->where(['isDeleted' => false])->all() - 查已软删数据:
Item::find()->where(['isDeleted' => true])->all() - 在
search()方法里漏掉这句,后台列表就会显示已删项;前端 API 若没加,APP 端可能拿到脏数据 - 想全局屏蔽软删记录?可以重写模型的
find()方法,返回自定义 Query 类,但更推荐在每个业务查询处显式加条件——清晰、可控、不隐式
deleteAll() 和软删除根本不是一回事
deleteAll() 是硬删,绕过所有模型层逻辑,包括 SoftDeleteBehavior。它不会更新 isDeleted 字段,而是直接执行 SQL DELETE FROM ...。
- 批量软删不能用
deleteAll(),得用updateAll():Item::updateAll(['isDeleted' => true], ['id' => $ids]) - 如果真要批量硬删(比如清理归档表),必须确认行为没开启
replaceRegularDelete,否则deleteAll()反而被拦截成软删,导致误判 - 注意
updateAll()不触发beforeSave/afterSave,所以如果你在beforeSave里做了日志或关联更新,这里会跳过
isDeleted = false,前端就可能展示已归档数据。











