商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > ThinkPHP 6.0 实现数据软删除后的物理清理脚本【Crontab】

ThinkPHP 6.0 实现数据软删除后的物理清理脚本【Crontab】

  发布于2026-07-11 阅读(0)

扫一扫,手机访问

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

ThinkPHP 6.0 实现数据软删除后的物理清理脚本【Crontab】

在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 来注册这个命令(如果框架没有自动注册的话)。

配置Crontab定时触发

第一步,先测试命令能否正常运行。在终端里执行 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');),再次运行命令,确认原来的记录还在——这说明事务回滚生效了,关联清理逻辑是安全的。

本文转载于:https://www.php.cn/faq/2808675.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注