发布于2026-07-11 阅读(0)
扫一扫,手机访问
需用模型force()机制定期物理清理软删除超30天数据:先确认模型启用SoftDelete、$useSoftDelete=true、delete_time字段存在且配置正确,再通过命令行任务调用onlyTrashed()->where('delete_time', '<', $thirtyDaysAgo)->force()安全清理。

在ThinkPHP项目中,软删除是个很实用的功能,但时间一长,那些标记为“已删除”的数据就像积灰一样,越堆越多,拖累查询效率。所以,定期把这些过期数据从数据库里彻底移除,就成了运维中绕不开的一环。这不是跑个SQL就能完事儿的,关键在于利用模型层的force()机制触发事件钩子,同时还要处理好并发和误删的问题。
上手之前,先确认模型是否真的启用了软删除。打开对应的模型文件(比如 app\model\User.php),检查三个要素是否都到位:use think\model\concern\SoftDelete;、use SoftDelete;、protected $useSoftDelete = true;。这三个缺一个,delete()方法就会直接物理删除,后续的force()也就无从谈起。
数据库里,对应的表必须有一个 delete_time 字段,类型最好是 DATETIME,默认值设为 NULL。如果字段名不是标准的 delete_time,那得在模型里显式声明 protected $deleteTime = 'xxx';。
另外,别忘了执行 php think optimize:schema 命令刷新模型缓存,否则旧的结构可能导致 onlyTrashed() 压根查不到数据,那后续操作就全白费了。
接下来,在 app/command 目录下新建一个 CleanSoftDeleted.php 文件。把下面的代码贴进去,注意把 App\Model\User 替换成你自己的模型类名,时间条件这里设的是30天前:
setName('clean:softdeleted')
->setDescription('物理清理软删除超过30天的数据');
}
protected function execute(Input $input, Output $output)
{
$thirtyDaysAgo = date('Y-m-d H:i:s', strtotime('-30 days'));
// 先统计数量,写入日志便于追溯
$count = User::onlyTrashed()
->where('delete_time', '<', $thirtyDaysAgo)
->count();
$output->writeln("待物理删除记录数:{$count}");
if ($count === 0) {
$output->writeln('无符合条件数据,退出');
return 0;
}
// 开启事务,确保关联清理不中断
Db::transaction(function () use ($thirtyDaysAgo, $output) {
User::onlyTrashed()
->where('delete_time', '<', $thirtyDaysAgo)
->force()
->delete();
$output->writeln('物理删除成功');
});
}
}
保存后,在项目根目录执行 php think make:command clean:softdeleted 来注册这个命令(如果框架没有自动注册的话)。
第一步,先测试命令能否正常运行。在终端里执行 php think clean:softdeleted,观察输出是否显示“物理删除成功”,同时确认数据库中对应的记录真的消失了。如果报错,重点检查模型路径、字段名和时间格式是否匹配。
第二步,编辑服务器的crontab。执行 crontab -e,添加一行(假设项目路径是 /var/www/myapp):
0 2 * * * cd /var/www/myapp && /usr/bin/php think clean:softdeleted >> /var/log/think-clean.log 2>&1
这行配置的意思是每天凌晨2点执行一次。注意,php必须使用绝对路径,否则cron环境可能会找不到它。
第三步,加上flock防并发(这一点很关键)。如果清理脚本执行时间可能超过1分钟(比如要删几万条记录),就需要防止cron重复启动实例,避免锁表或重复删除。修改crontab为:
0 2 * * * cd /var/www/myapp && flock -n /tmp/clean_softdeleted.lock -c "/usr/bin/php think clean:softdeleted >> /var/log/think-clean.log 2>&1"
验证方法有好几个。最直接的是查看日志文件:执行 tail -f /var/log/think-clean.log,每次执行时应该能看到“待物理删除记录数:X”和“物理删除成功”。如果出现PHP错误或MySQL超时,日志里会留下明确的记录。
也可以手动模拟过期数据。在数据库里执行 UPDATE user SET delete_time = '2025-01-01 00:00:00' WHERE id = 123;,然后运行 php think clean:softdeleted,确认这条记录被真正删除了,而不仅仅是更新了 delete_time 字段。
还有一个重要的安全验证:检查事务是否正常工作。在 execute() 方法中故意抛出一个异常(比如 throw new Exception('test rollback');),再次运行命令,确认原来的记录还在——这说明事务回滚生效了,关联清理逻辑是安全的。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8