Laravel 9中updateOrInsert仅插入不更新问题求助
Laravel 9 updateOrInsert 始终执行插入不更新的问题排查与解决
问题场景
在Laravel 9项目中使用updateOrInsert方法实现数据去重,期望存在匹配记录时执行更新,不存在时执行插入,但实际始终触发插入操作,更新功能失效。以下是原代码实现:
<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\DB; use Illuminate\Http\Request; use App\Models\Wip; use App\Models\db2; class WipController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index(Request $request) { $tgl_skrg = date('Y-m-d 00:00:00'); $tgl_skrg2 = date('Y-m-d 23:00:00'); $nilai = '00017'; $db2s = DB::connection('mysql2')->table("wip_tracking_1")->get(); $data = json_decode($db2s, true); foreach ($data as $db2 ){ DB::table('wip_tracking') ->updateOrInsert( [ "TP" =>$db2 ['TP'], "TP_code"=>$db2 ['TP_code'], "VIN"=>$db2 ['VIN'] , "Flag"=>$db2 ['Flag'] , "Suffix"=>$db2 ['Suffix'] , "Color_Code"=>$db2 ['Color_Code'] , "Scan_date"=>$db2 ['Scan_date'] , "Production_date"=>$db2 ['Production_date'] , "Production_shift"=>$db2 ['Production_shift'] , "Model_code"=>$db2 ['Model_code'] , "Brand"=>$db2 ['Brand'] , "Destination_code"=>$db2 ['Destination_code'] , "WIP_code"=>$db2 ['WIP_code'] , "ADM_Production_ID"=>$db2 ['ADM_Production_ID'] , "Plan_delivery_date"=>$db2 ['Plan_delivery_date'] , "created_at" => date('Y-m-d H:i:s'), ], [ "ADM_Production_ID"=> $db2['ADM_Production_ID'] ], [ "VIN"=> $db2['VIN'] ], ); } }
错误原因
updateOrInsert方法仅接受两个参数:
- 第一个参数:用于判断记录是否存在的查询条件数组(通常是唯一标识字段)
- 第二个参数:记录存在时要更新的字段,或不存在时要插入的字段数组
原代码存在两个核心错误:
- 传入三个参数,超出方法定义,第三个参数会被直接忽略
- 第一个参数包含了
created_at(每次执行都会生成新时间)以及大量非唯一字段,导致每次查询都无法匹配到已有记录,因此始终触发插入操作
解决方案
修正updateOrInsert的参数结构,以业务唯一标识字段(如VIN,车辆识别码通常全局唯一)作为查询条件,将所有需要同步的字段放在第二个参数中。同时遵循Laravel规范,新增updated_at记录更新时间,created_at仅在插入时设置。
修正后的代码示例:
<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\DB; use Illuminate\Http\Request; use App\Models\Wip; use App\Models\db2; class WipController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index(Request $request) { $tgl_skrg = date('Y-m-d 00:00:00'); $tgl_skrg2 = date('Y-m-d 23:00:00'); $nilai = '00017'; $db2s = DB::connection('mysql2')->table("wip_tracking_1")->get(); $data = json_decode($db2s, true); foreach ($data as $db2 ){ DB::table('wip_tracking') ->updateOrInsert( // 第一个参数:查询条件,用唯一标识VIN判断记录是否存在 ["VIN" => $db2['VIN']], // 第二个参数:要插入或更新的所有字段 [ "TP" => $db2['TP'], "TP_code" => $db2['TP_code'], "Flag" => $db2['Flag'], "Suffix" => $db2['Suffix'], "Color_Code" => $db2['Color_Code'], "Scan_date" => $db2['Scan_date'], "Production_date" => $db2['Production_date'], "Production_shift" => $db2['Production_shift'], "Model_code" => $db2['Model_code'], "Brand" => $db2['Brand'], "Destination_code" => $db2['Destination_code'], "WIP_code" => $db2['WIP_code'], "ADM_Production_ID" => $db2['ADM_Production_ID'], "Plan_delivery_date" => $db2['Plan_delivery_date'], "created_at" => DB::raw('IFNULL(created_at, NOW())'), // 插入时设为当前时间,更新时保留原值 "updated_at" => date('Y-m-d H:i:s') // 每次操作更新时间 ] ); } } }
补充说明
- 如果业务中
ADM_Production_ID也是唯一标识,可将查询条件改为["ADM_Production_ID" => $db2['ADM_Production_ID']],或组合多个唯一字段(如["VIN" => $db2['VIN'], "ADM_Production_ID" => $db2['ADM_Production_ID']]) - 确保
wip_tracking表中用于查询的字段(如VIN)已添加唯一索引,避免重复数据并提升查询效率
内容的提问来源于stack exchange,提问作者BossRana
相关产品推荐
相关产品推荐

