跳转到主内容
极星编程网:以代码为星,赴技术山海!

ThinkPHP批量写入怎么写_ThinkPHP模型批量保存技巧【汇总】

saveAll()只插一条或报错,因其本质是循环调用单条save(),每条均执行验证、事件、自动时间戳等完整模型生命周期;任一条数据验证失败、字段不匹配或钩子异常即中断,且默认不回滚。 saveAll() 为什么只插了一条或直接报错 ThinkPHP 的
saveAll()
看似简单,但实际行为高度依赖模型定义和数据结构。它不是“把数组全塞进去”,而是对每个元素调用
save()
,所以每条数据都走完整模型生命周期:验证、自动写入、事件钩子、字段过滤。 常见失败点:
saveAll()
传入的数组里,某条数据触发了验证失败(比如空邮箱),整个操作就中断,前面成功的也不会回滚 —— 默认不开启事务 数据字段不统一,比如第一条有
['name', 'email']
,第二条多出
'phone'
,而模型没定义该字段且未设
protected $schema
,MySQL 直接报
Unknown column 'phone'
用了
$model->allowField(true)
但没在每次循环里重置,导致后续条目被上一条残留的 allowField 策略干扰 模型启用了
$autoWriteTimestamp = true
,但某条数据手动传了
'create_time' => null
,MySQL 严格模式下插入失败 insertAll() 和 saveAll() 到底选哪个 核心区别不在“快慢”,而在“走不走模型逻辑”:
insertAll()
是 Db 层方法,跳过模型验证、获取器、修改器、事件、自动时间戳,纯 SQL 批量 INSERT。适合导入清洗过的原始数据(如 Excel 解析后)、后台脚本、高吞吐场景
saveAll()
是模型方法,每条都实例化模型对象、触发
beforeWrite
、
afterWrite
、检查
$readonly
、执行
setAttr()
。适合需要业务校验、关联处理、日志埋点的常规批量保存 性能上,
insertAll()
通常快 3–5 倍,但丢了模型层所有防护;
saveAll()
慢,但能捕获单条失败并定位到具体哪一行哪一列 别混用:用
Db::table('user')->insertAll($data)
就别指望
createTime
自动写入;用
UserModel::saveAll($data)
就别绕过模型去手动拼 SQL 批量写入时 create_time/update_time 不生效? 自动时间戳不是“全局开关”,它只在满足全部条件时才工作: PHP 8.5.5 PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。 下载 立即学习 “ PHP免费学习笔记(深入) ”; 模型中必须显式声明
protected $autoWriteTimestamp = true;
(5.1/6.x 都要) 数据库字段名得匹配(默认是
create_time
/
update_time
),否则要配
protected $createTime = 'add_time';
字段类型要是
DATETIME
或
TIMESTAMP
;如果是
INT
,还得加
protected $type = ['create_time' => 'integer'];
saveAll()
中每条记录都算一次独立
save()
,所以每条都会写
create_time
;但
update_time
只有“检测到字段值变更”才更新,不是每条都刷 如果用
insertAll()
,自动时间戳完全不触发 —— 它压根不进模型层 大数量导入卡死或内存爆掉怎么办 ThinkPHP 默认把整张 Excel 或 CSV 全读进内存再处理,几万行就容易 OOM。真实项目必须分片: Excel 导入时,用
$spreadsheet->getActiveSheet()->getRowIterator(2)
从第 2 行开始迭代,配合
yield
或手动分批(比如每 500 行
insertAll()
一次) CSV 导入别用
file_get_contents()
全读,坚持用
fopen()
+
fgetcsv()
流式读取,边读边入库 无论哪种方式,务必手动开启事务:
Db::startTrans(); try { ... insertAll(); ... } catch (\Exception $e) { Db::rollback(); throw $e; }
索引很重要:批量 WHERE 更新或关联查询前,确认
id
、
status
等常用条件字段有数据库索引,否则
saveAll()
后续的关联更新可能锁表几十秒 字段名大小写、虚拟字段追加、验证规则动态注入这些细节,表面看是“锦上添花”,实际在线上批量场景里,往往一条数据格式不对,整批就静默丢弃或报错中断。模型层的每道闸门,都得亲手验过才敢放行。

相关文章