codeigniter 4软删除需同时满足三条件:模型启用软删除、表中存在匹配类型的deleted_at字段、调用模型delete()方法;否则回退硬删除。

CodeIgniter 4 的软删除不会自动生效,必须同时满足三个条件:模型启用了软删除、表中存在对应的时间戳字段、且调用的是模型的 delete() 方法(而非查询构建器的 delete())。
为什么设置了 $useSoftDelete = true 却还是硬删除?
最常见原因是——你没在数据库表里加 deleted_at 字段,或者字段名和模型配置不一致。CI4 的软删除本质是把 deleted_at 字段设为当前时间戳,而不是执行 SQL DELETE。如果该字段不存在或类型不对(比如是 VARCHAR 而非 DATETIME 或 TIMESTAMP),模型会静默回退到硬删除。
- 检查你的迁移文件或建表语句,确保有类似
deleted_at DATETIME NULL的字段 - 确认模型中
$deletedField值与数据库字段名完全一致(默认是'deleted_at') - 别在控制器里直接调用
$this->db->table('xxx')->delete()—— 这绕过了模型逻辑,必然硬删 - 如果你用的是自定义主键(如
user_id),要确保$primaryKey正确设置,否则模型可能无法定位记录
delete() 方法到底走软删还是硬删?
取决于调用上下文:
- 通过模型实例调用:
$userModel->delete($id)→ 尊重$useSoftDelete配置,软删(前提是字段存在) - 通过查询构建器调用:
$this->db->table('users')->delete(['id' => $id])→ 强制硬删,不查模型配置 - 批量操作:
$userModel->delete([1,2,3])→ 同样走软删;但$userModel->purgeDeleted()才真正物理删除已软删的记录 - 注意:
delete(null, false)可强制跳过软删(第二个参数为false),但一般没必要
软删除后查询自动过滤被删数据吗?
是的,但仅限于模型的常规查询方法(find()、findAll()、where() 链式调用等)。CI4 默认会在 WHERE 条件末尾追加 AND deleted_at IS NULL。
- 如果你想查包括已软删的记录,用
$model->withDeleted()->find($id) - 只查已软删的:用
$model->onlyDeleted()->findAll() - 手动清除软删标记(恢复数据):
$model->restore($id),它会把deleted_at设为NULL - 别用
update()直接改deleted_at字段——虽然能行,但绕过了restore()的钩子和类型校验
容易被忽略的兼容性细节
软删除不是“开个开关就完事”,几个边界情况常导致行为异常:
-
$useTimestamps必须为true,否则$deletedField不会被写入值(CI4 源码里软删依赖时间戳机制) - MySQL 5.6+ 推荐用
TIMESTAMP类型并设默认NULL;避免用INT存 Unix 时间戳,CI4 不识别 - 如果模型继承了自定义基类,请确认基类没覆盖
delete()或重置$useSoftDelete - 软删除不触发
beforeDelete回调,而是触发beforeSoftDelete—— 如果你写了钩子,得换名字
最麻烦的一点:迁移时加 deleted_at 字段后,旧数据的该字段全是 NULL,这没问题;但如果你中途关闭又开启 $useSoftDelete,已存在的非空 deleted_at 值不会自动被识别为“已软删”,得靠 onlyDeleted() 手动捞出来确认状态。











