ThinkPHP模型save()字段自动归档失效的主因是未显式配置$autoWriteTimestamp和$type类型映射;历史表迁移需用chunk分批避免OOM,且须注意软删除冲突及cron工作路径问题。

ThinkPHP 模型 save() 时字段自动归档失效?检查 autoWriteTimestamp 和 type 配置
自动归档不是默认开启的,它依赖时间戳字段的显式声明和类型映射。如果你发现 create_time 或 update_time 没有写入,大概率是模型里漏了配置。
-
protected $autoWriteTimestamp = true;必须显式设置,即使全局开启也不代表模型生效 - 时间字段必须在
protected $type = [];中声明为datetime或timestamp,否则 TP 会当字符串处理,不触发自动赋值 - 如果字段名不是默认的
create_time/update_time,得用protected $createTime = 'added_at';和protected $updateTime = 'modified_at';显式指定
历史表迁移用 Db::table()->where()->chunk() 而不用 select()->each()
一次性查几万条再遍历插入,容易 OOM 或超时;each() 看似简洁,但底层仍会把全部结果加载进内存。
- 用
chunk(500, function($list) { ... })分批拉取,每批处理完自动释放内存 - 迁移前先用
Db::table('data')->where('status', 'expired')->count()预估量级,决定是否加索引(比如给status+created_at建联合索引) - 别在事务里包整个 chunk —— 单批失败不影响后续,且避免长事务锁表;真要强一致性,只对单批做事务即可
移入历史表后原记录删不掉?注意 deleteTime 软删除字段冲突
如果模型启用了软删除(use SoftDelete;),delete() 实际只是更新 delete_time 字段,不会真正删除 —— 这会导致你“以为移走了”,其实还在原表挂着。
- 确认迁移逻辑里调的是
Db::table('origin')->where(...)->delete()(硬删),而不是模型实例的$model->delete() - 如果必须用模型操作,得临时禁用软删除:
Model::withoutSoftDelete()->where(...)->delete() - 历史表字段结构要和原表一致,尤其注意
delete_time字段在历史表中应设为 NULLABLE,否则硬删后补过去会报错
定时任务跑迁移脚本,Cron 执行路径和 ThinkPHP 环境不一致
直接写 php think migrate:to_history 在命令行能跑,但加到 crontab 就报错“Class not found”或“Cannot load config”,基本是工作目录或环境变量没对上。
- crontab 里必须写绝对路径:
/usr/bin/php /var/www/myapp/think migrate:to_history - 加
cd /var/www/myapp &&前缀,确保自动加载和配置能正常读取 - TP 的
Env是基于当前运行目录判断环境的,cron 默认在/root或/var/spool/cron下执行,不 cd 就找不到.env
实际跑通的关键,往往卡在软删除配置和 cron 工作路径这两个点上——它们不报明显错误,但会让数据“看似动了,实则没动”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











