Laravel批量更新数据时报错及代码优化咨询
问题1:批量更新报错修复
报错原因
报错信息显示cash字段为整数类型,但你传入了数组[10000,10000],Laravel将数组转为字符串后不符合SQL整数格式要求,导致数据库抛出类型错误。核心问题是:Laravel的update()方法接收的是键值对,值必须是单个合法值,不能直接用数组批量更新多条记录的对应字段。
修复方案
替换原更新逻辑,循环处理每条需要更新的记录(更直观适配当前场景):
原错误代码:
if ($kriya->pluck('school_id') == $budget_data->pluck('school_id')) { Palika_ToSchool_Kriyakalap::whereIn('kriya_name', $budget_data->pluck('kriyakalap')) ->whereIn('school_id', $budget_data->pluck('school_id')) ->update(['cash' => $newArray]); }
改为:
// 检查是否存在需要更新的记录 if ($kriya->isNotEmpty()) { // 遍历每条记录,对应更新cash值 foreach ($kriya as $index => $item) { $item->update([ 'cash' => $newArray[$index] ]); } }
注:原判断条件$kriya->pluck('school_id') == $budget_data->pluck('school_id')逻辑不准确,集合直接用==比较可能不符合预期,改为检查$kriya是否非空即可。
问题2:代码优化与编码技能提升
现有代码的明显问题
- 重复冗余查询:
$budget_data中重复写了两次where('biniyojan_id', $biniyojan_id);$budget_cash的查询可合并到$budget_data中,避免重复访问数据库。 - 变量命名错误:
$upudate拼写错误,应为$update。 - 插入逻辑错误:
Palika_ToSchool_Kriyakalap::where('kriya_name' != $bud->kriyakalap)->insert($data)写法违规,正确格式是where('kriya_name', '!=', $bud->kriyakalap),且该逻辑未判断记录是否存在,可能导致重复插入。 - 控制器臃肿:所有业务逻辑堆在控制器方法中,违反单一职责原则,后期维护难度大。
优化建议
1. 使用Laravel Upsert简化逻辑
Laravel提供upsert()方法,专门处理「存在则更新,不存在则插入」的场景,大幅简化代码:
// 整理需要批量处理的数据 $upsertData = $budget_data->map(function ($bud) { // 获取现有记录的cash值,无则默认为0 $existingCash = Palika_ToSchool_Kriyakalap::where('school_id', $bud->school_id) ->where('kriya_name', $bud->kriyakalap) ->value('cash') ?: 0; return [ 'school_id' => $bud->school_id, 'kriya_name' => $bud->kriyakalap, 'cash' => $existingCash + $bud->cash, 'created_at' => now(), 'updated_at' => now() ]; })->toArray(); // 执行upsert:第二个参数是联合唯一索引(用于判断记录是否存在),第三个参数是需要更新的字段 Palika_ToSchool_Kriyakalap::upsert( $upsertData, ['school_id', 'kriya_name'], ['cash', 'updated_at'] );
注:需在palika_to_school_kriyakalap表中给school_id和kriya_name添加联合唯一索引,否则upsert无法正常工作。
2. 抽离业务逻辑到模型
将业务逻辑从控制器中分离,放到Palika_ToSchool_Kriyakalap模型中:
// Palika_ToSchool_Kriyakalap.php 模型文件 public static function syncFromBiniyojan($biniyojanId) { $budgetData = BiniyojanDetails::where('biniyojan_id', $biniyojanId)->get(); $upsertData = $budgetData->map(function ($bud) { $existingCash = self::where('school_id', $bud->school_id) ->where('kriya_name', $bud->kriyakalap) ->value('cash') ?: 0; return [ 'school_id' => $bud->school_id, 'kriya_name' => $bud->kriyakalap, 'cash' => $existingCash + $bud->cash, 'created_at' => now(), 'updated_at' => now() ]; })->toArray(); return self::upsert( $upsertData, ['school_id', 'kriya_name'], ['cash', 'updated_at'] ); }
控制器代码简化为:
public function approve(Request $request, $biniyojan_id) { $update = DB::table('biniyojan') ->where('biniyojan_id', $biniyojan_id) ->update(['biniyojan_status' => 1]); if ($update) { Palika_ToSchool_Kriyakalap::syncFromBiniyojan($biniyojan_id); return redirect()->back()->with('status', 'Approved!!!'); } return redirect()->back()->with('error', 'Error!!!'); }
3. 添加事务保证数据一致性
确保更新biniyojan状态和同步数据的操作要么全部成功,要么全部回滚:
use Illuminate\Support\Facades\DB; public function approve(Request $request, $biniyojan_id) { DB::beginTransaction(); try { $update = DB::table('biniyojan') ->where('biniyojan_id', $biniyojan_id) ->update(['biniyojan_status' => 1]); if (!$update) { throw new \Exception('Failed to update biniyojan status'); } Palika_ToSchool_Kriyakalap::syncFromBiniyojan($biniyojan_id); DB::commit(); return redirect()->back()->with('status', 'Approved!!!'); } catch (\Exception $e) { DB::rollBack(); return redirect()->back()->with('error', 'Error!!!'); } }
编码技能提升方向
- 吃透Eloquent ORM:熟练掌握关联关系、查询构造器、批量操作等功能,减少重复代码。
- 遵循SOLID原则:控制器只处理请求和响应,业务逻辑交给模型或服务类。
- 严格代码规范:遵循PSR-12命名规范,变量名清晰易懂,添加必要注释。
- 掌握调试技巧:用
Log::info()输出中间变量,或dd()调试数据集合,高效排查问题。 - 学习数据库优化:合理添加索引,减少不必要的查询,提升系统性能。
内容的提问来源于stack exchange,提问作者Rajan Sharma
相关产品推荐
相关产品推荐

