Laravel批量插入多行数据并获取插入主键的问题
问题:Laravel批量插入多维数组报错,需批量插入并获取主键
报错信息
"...", "message": "Array to string conversion", "exception": "ErrorException", "file": "/home/deepan8/pich.abc.com/vendor/laravel/framework/src/Illuminate/Support/Str.php", "line": 762, "trace": [ { "file": "/home/deepan8/pich.abc.com/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php", "line": 257, "function": "handleError", "class": "Illuminate\\Foundation\\Bootstrap\\HandleExceptions", "type": "->" } ]
代码片段
$voucherArray = []; foreach($users as $user) { $voucherArray[] = ['voucher_code' => rand(10000, 999999), 'voucher_price' => $request->price, 'expiry_date' => $request->date, 'status' => "Active", ]; } $ids = DB::table('pich_voucher')->insertGetId($voucherArray); foreach($ids as $id) { }
需求:一次性插入所有行提升性能,同时获取插入后的主键ID。
解决方案
问题根源
insertGetId()仅支持单条数据插入,传入多维数组会触发类型转换错误,这就是你看到"Array to string conversion"报错的原因。
实现批量插入+获取主键的方案
方案1:事务包裹循环插入(兼顾性能与原子性)
适合数据量中等(千级以内)的场景,事务保证所有插入操作原子性,性能损耗远低于无事务的循环插入:
$ids = []; DB::transaction(function () use ($users, $request, &$ids) { foreach($users as $user) { $id = DB::table('pich_voucher')->insertGetId([ 'voucher_code' => rand(10000, 999999), 'voucher_price' => $request->price, 'expiry_date' => $request->date, 'status' => "Active", ]); $ids[] = $id; } }); // 后续处理逻辑 foreach($ids as $id) { // ... }
方案2:原生SQL批量插入+主键计算(适合大数据量)
利用MySQL自增主键的连续性,通过原生SQL实现真正的批量插入,再推导所有插入的ID(仅适用于MySQL+自增主键场景):
// 构建批量插入SQL $columns = ['voucher_code', 'voucher_price', 'expiry_date', 'status']; $values = []; $pdo = DB::getPdo(); foreach($users as $user) { $values[] = sprintf( "(%d, %s, %s, %s)", rand(10000, 999999), $pdo->quote($request->price), $pdo->quote($request->date), $pdo->quote("Active") ); } $sql = sprintf( "INSERT INTO pich_voucher (%s) VALUES %s", implode(',', $columns), implode(',', $values) ); // 执行插入并计算主键 DB::statement($sql); $startId = $pdo->lastInsertId(); $rowCount = $pdo->rowCount(); $ids = range($startId, $startId + $rowCount - 1); // 后续处理逻辑 foreach($ids as $id) { // ... }
注意:若存在并发插入操作,或主键非连续自增,该方法会导致ID数组不准确。
方案3:Eloquent模型的saveMany()(封装性更好)
如果使用Eloquent模型,可通过关联关系的saveMany()方法实现,内部仍为循环插入,但封装更简洁:
$vouchers = []; foreach($users as $user) { $vouchers[] = new Voucher([ 'voucher_code' => rand(10000, 999999), 'voucher_price' => $request->price, 'expiry_date' => $request->date, 'status' => "Active", ]); } // 若存在关联关系,可直接调用saveMany // $user->vouchers()->saveMany($vouchers); // 直接批量保存(无关联) Voucher::saveMany($vouchers); // 获取所有ID $ids = $vouchers->pluck('id')->toArray();
注意事项
- 批量插入时需关注数据库
max_allowed_packet配置,避免SQL语句过长触发报错; - 若使用方案2,需确保表无其他并发插入操作,否则主键推导会失效。
内容的提问来源于stack exchange,提问作者Junaid Ali Ansari
相关产品推荐
相关产品推荐

