ThinkPHP6定时任务批量处理核心是分批可控、环境稳定、失败可溯、资源不崩:需LIMIT+ORDER BY分页拉取、显式多库连接、原生SQL插入、CLI手动初始化DB与日志通道、crontab绝对路径调度、断点续传机制。

ThinkPHP 6 实现定时任务批量数据处理,核心不是“写个循环跑完”,而是解决分批可控、环境稳定、失败可溯、资源不崩这四个实际问题。直接在 execute() 里查十万条再 foreach 插入,大概率内存溢出或超时中断。
分批拉取与写入必须解耦
千万级流水同步这类场景,不能一次性 load 全量再 insertAll。要主动控制每批次数据量,并确保源库和目标库的连接隔离。
- 用 LIMIT + ORDER BY id 分页拉取,避免 OFFSET 深度翻页性能退化;例如每次取 1000 条且按主键升序,记录上一批最大 ID 作为下一批起点
- 源库和目标库必须显式调用 Db::connect('source') 和 Db::connect('target'),不能混用默认连接,否则事务或字符集可能错乱
- 插入优先走原生 SQL 拼接(含字段名白名单校验),比模型 save() 或 insertAll() 更可控;若需字段转换,应在 fetch 后、insert 前做映射,不依赖模型自动填充
CLI 环境下数据库与日志必须手动兜底
Web 请求中自动初始化的容器组件,在命令行里不会自动加载,不处理就会静默报错或空转。
- 执行前加 app('db')->connect() 强制初始化主库连接;若用多个连接,对每个都调用一次 connect()
- 日志不能只用 Log::info(),必须指定 channel:Log::channel('cron')->info('batch 1-1000 synced'),否则内容可能被丢弃到空通道
- 避免使用 $this->app->db 这类依赖容器自动注入的写法;改用 Db::connect() 或通过 execute() 方法参数注入(如 public function execute(Input $input, Output $output, Connection $db))
定时调度必须走系统 crontab,不能靠 PHP 循环模拟
TP6 自身没有内置守护进程调度器,任何 while(true) sleep(60) 的方式都不可靠——进程意外退出无人拉起,也无法跨服务器协调。
- crontab 规则必须写绝对路径:/www/server/php/82/bin/php /www/wwwroot/myapp/think sync:log --limit=1000 >> /www/wwwroot/myapp/runtime/log/sync.log 2>&1
- 务必 cd 切换工作目录:* * * * * cd /www/wwwroot/myapp && /www/server/php/82/bin/php think sync:log
- 测试阶段先设为 * * * * *(每分钟),确认日志生成、数据库有写入、无 Class not found 报错,再逐步放宽周期
异常与中断需有明确恢复机制
批量任务中途失败很常见(网络抖动、锁表、磁盘满),不能每次从头开始,也不能跳过断点。
- 每次执行前先查目标表当前最大 ID,作为本次同步起点;不要硬编码 “从 0 开始” 或 “从昨天开始”
- 在事务外做批次标记:用一张 small_table 记录 last_sync_id、table_name、sync_time,每次成功写入后更新它
- catch 异常后,记录错误详情(包括当前批次范围、SQL、堆栈),并 exit(1),让 crontab 下次重试——避免 silent fail 导致数据停滞
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











