Laravel中saveMany()/createMany()执行多插入查询而非单查询问题
问题描述
使用Laravel 9 + PHP 8.1.0开发,Order与OrderProduct是一对多(HasMany/BelongsTo)关联,保存订单项时,期望通过saveMany()用单条批量插入查询完成操作,但实际生成了N条独立的INSERT语句,切换到createMany()后结果一致。
代码逻辑是从未入库的$calculation模型实例中获取产品数据,通过foreach创建本地OrderProduct对象,再调用saveMany()保存。
相关代码
问题函数
public function createOrderItems(Order $calculation, Order $order): void { $order_products = []; foreach ($calculation->getProducts() as $product) { $order_products[] = new OrderProduct([ 'product_id' => $product->product_id, 'quantity' => $product->quantity, 'price_with_pdv' => $product->price_with_pdv, 'price_without_pdv' => $product->price_without_pdv, 'weight' => $product->weight, ]); } $order->orderProducts()->saveMany($order_products); }
函数调用
$this->createOrderItems($calculation, $order);
Order模型关联
public function orderProducts(): HasMany { return $this->hasMany(OrderProduct::class); }
Telescope日志
insert into `order_products` (`product_id`, `quantity`, `price_with_pdv`, `price_without_pdv`, `weight`... 0.33ms insert into `order_products` (`product_id`, `quantity`, `price_with_pdv`, `price_without_pdv`, `weight`... 0.34ms insert into `order_products` (`product_id`, `quantity`, `price_with_pdv`, `price_without_pdv`, `weight`... 0.50ms insert into `order_products` (`product_id`, `quantity`, `price_with_pdv`, `price_without_pdv`, `weight`... 0.30ms insert into `order_products` (`product_id`, `quantity`, `price_with_pdv`, `price_without_pdv`, `weight`... 0.45ms
解决方案
原因说明
Laravel的saveMany()和createMany()方法并非执行批量插入,它们会循环处理每个模型实例,单独执行INSERT语句。这是因为这两个方法需要触发模型的creating/created事件、处理观察者、自动填充时间戳(如created_at/updated_at)以及关联的外键赋值,无法通过单条批量插入完成这些逻辑。
实现批量插入的方法
如果不需要触发模型事件,仅需高效批量插入数据,可以直接构建批量数据数组,使用OrderProduct::insert()实现:
public function createOrderItems(Order $calculation, Order $order): void { $orderProductsData = []; $now = now(); // 手动填充时间戳(如果模型开启$timestamps=true) foreach ($calculation->getProducts() as $product) { $orderProductsData[] = [ 'order_id' => $order->id, // 手动赋值外键 'product_id' => $product->product_id, 'quantity' => $product->quantity, 'price_with_pdv' => $product->price_with_pdv, 'price_without_pdv' => $product->price_without_pdv, 'weight' => $product->weight, 'created_at' => $now, 'updated_at' => $now, ]; } OrderProduct::insert($orderProductsData); }
注意事项
- 如果需要触发模型事件或使用Eloquent的其他特性,只能接受
saveMany()的单条插入逻辑,或者手动触发对应事件。 - 批量插入时,需要手动处理外键(
order_id)和时间戳字段(如果模型开启了$timestamps)。 - 确保批量数据数组的每个元素字段与数据库表字段完全匹配,避免字段缺失或错误。
内容的提问来源于stack exchange,提问作者Leon Kardaš
相关产品推荐
相关产品推荐

