Laravel模型在try/catch中更新后保留错误值的原因咨询
问题描述
在Laravel中更新数据库数据时,deployment_id列是唯一约束列。当尝试用重复值更新该字段触发唯一约束错误后,在catch块中仅更新模型的inprogress和error字段,却再次触发相同的唯一约束错误。
简化代码如下:
public $defaultModel ; function errorTest(){ $this->defaultModel = $inprogress = Process::where('inprogress' , 1 )->first(); try { $inprogress->update( [ 'deployment_id' => 666 , ]); } catch (\Exception $exception) { $this->defaultModel->update([ 'inprogress' => 0 , 'error'=>'duplicate' ]); } }
触发的SQL错误:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '666' for key 'process_deployment_id_unique'
排查发现错误来自catch块的更新操作:即使未在catch中修改deployment_id列,模型仍保留try块中设置的deployment_id=666值,导致再次触发唯一约束错误。仅通过重新从数据库拉取模型再更新才能解决:
$model = $this->defaultModel->fresh(); $model->update([ 'inprogress' => 0 , 'error'=>'duplicate' ]);
原因解释
Laravel的Eloquent模型是内存中的数据对象:当在try块调用$inprogress->update(['deployment_id' => 666])时,虽然数据库层面因唯一约束更新失败,但Eloquent已经将内存中模型实例的deployment_id属性修改为666。
进入catch块调用$this->defaultModel->update()时,Eloquent会基于内存中当前模型的所有属性生成更新语句——它会把已被修改为666的deployment_id也包含在更新字段里,自然再次触发唯一约束错误。
而fresh()方法会从数据库重新获取该模型的最新数据,覆盖内存中被修改过的属性,此时模型的deployment_id恢复为数据库里的原始值,再执行更新就不会携带重复的666值,也就不会触发约束错误了。
内容的提问来源于stack exchange,提问作者hretic
相关产品推荐
相关产品推荐

