不能。在同一个事务中混用saveAll()和insertAll()会导致事务失效,因二者使用不同数据库连接实例,MySQL事务仅对单连接有效,易引发“半提交”;应统一选用其一并按场景分工。

不能。在同一个事务里混用 saveAll() 和 insertAll() 会导致事务失效。
底层连接不一致是根本原因
saveAll() 是模型方法,走模型层,使用模型绑定的数据库连接实例;insertAll() 是 Db 类方法,走查询构建器,可能使用独立的 PDO 连接实例。即使都在 Db::transaction() 包裹下,两个操作也可能落在不同连接上——而 MySQL 事务只对单个连接有效。
- TP5.1+ 和 TP6 中该问题更常见,尤其在连接池或长连接复用场景下
- 现象是:一部分数据写入成功,另一部分失败后未回滚,出现“半提交”状态
- 调试时难以察觉,因为无报错,仅逻辑异常
两者设计目标完全不同
saveAll() 和 insertAll() 不是“可互换的批量插入方式”,而是面向不同场景的工具:
- saveAll():适合小批量(≤100 条)、需验证/事件/自动时间戳/字段过滤的业务写入,比如后台表单提交
- insertAll():适合大批量(数百至数万条)、数据已清洗、追求性能与内存效率的导入场景,如 Excel 解析入库
正确做法:选一个,坚持到底
事务内必须统一使用同一种方式,且推荐按场景明确分工:
立即学习“PHP免费学习笔记(深入)”;
- 要验证和事件 → 全部用 saveAll(),并加 ['validate' => false, 'batch' => true] 提速,但别超 500 条/批
- 纯插入、高性能 → 全部用 Db::insertAll(),手动补全 create_time 等字段,并用 $batchSize 分片
- 务必用 Db::transaction() 包裹整个操作,不能只包 insertAll() 而漏掉 saveAll()
常见错误写法(务必避免)
以下代码看似合理,实则危险:
❌ 错误示例:Db::transaction(function () use ($data) {
(new User())->saveAll(array_slice($data, 0, 100));
Db::insertAll(array_slice($data, 100));
});
这种写法混合了模型连接和 Db 连接,事务无法覆盖全部操作。



















