在 try/catch 中更新模型:模型记住 catch 中错误的更新值

updating model in try/catch : model remembers faulty update values in the catch

提问人:hretic 提问时间:10/24/2023 最后编辑:hretic 更新时间:11/5/2023 访问量:137

问:

我有一个嵌套函数调用来更新数据库中的一些数据,我要更新的列在数据库中是唯一的,在这种情况下,它可能会使用重复值进行更新,我想将该模型/行标记为重复

这是我的代码的简化版本,没有嵌套的函数调用

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'
        ]);
    }
}

当我尝试使用重复值更新模型时,我不断收到 Laravel 错误页面

  SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '666' for key 
  'process_deployment_id_unique'

起初我以为可能是我的 try/catch 不起作用并且我无法捕获错误,但是在玩了之后,我发现错误是由 catch 部分引起的

        $this->defaultModel->update([
            'inprogress' => 0  ,
            'error'=>'duplicate'
        ]);

即使我没有更新 catch 中的唯一列,模型仍然会记住 try 正文中给出的值,并尝试在 catch 中使用值进行更新(deployment_id)deployment_id666

疯狂的部分是我什至没有在 catch 部分使用相同的变量!就好像它们在相互引用一样

唯一的解决方法是做一些类似的事情

        $model = $this->defaultModel->fresh();
        $model->update([
            'inprogress' => 0  ,
            'error'=>'duplicate'
        ]);

知道为什么会这样吗?

请不要建议其他方法或方法,我知道我可以使用不同的方法....我的问题是关于模型记住 CATCH 更新的尝试数据

php mysql laravel 异常

评论

0赞 Othmane Nemli 10/24/2023
使用事务提交回滚...这对你来说很容易

答:

-1赞 Robert S 11/2/2023 #1

您需要更改方法,首先检查数据库表中是否存在该 ID,如果是,您可以将该条目标记为重复,如果没有,则可以使用您的 ID 更新该列值。

评论

0赞 hretic 11/2/2023
谢谢我知道,但这不是我的问题阅读有关竞争条件,您的方法容易出现错误
1赞 Adi 11/3/2023 #2

因此,PHP 中的变量范围是按函数而不是按块。因此,当您在 try 块中分配变量时,您也可以在外部访问它,只要它们在同一个函数中即可。这就是为什么您在 catch 块中看到相同值的原因。

4赞 Olivier 11/3/2023 #3

Model::update() 方法的实现方式如下:

return $this->fill($attributes)->save($options);

这意味着首先更新模型对象,然后保存到数据库中。如果 SQL 查询失败,模型将保留新值,并且它们仍被视为脏值(即未与数据库同步)。

如果您再次调用同一模型,Eloquent 将尝试保存所有脏属性(在您的情况下,包括 )。update()deployment_id

请注意,在您的代码中,并引用相同的模型对象,因此使用一个或另一个将产生相同的效果。$this->defaultModel$inprogress

评论

0赞 Adi 11/5/2023
您能否提供说明它们被标记为脏污的来源?你的解释并不完全准确。它不会将任何属性标记为脏属性,如果 SQL 查询失败,模型对象将保持不变。
0赞 Olivier 11/5/2023
@Adi 该模型将原始值保留在$original中,将当前值保留在$attributes中。当属性的原始值和当前值不同时,该属性是脏的。成功时,它调用 ,调用 ,复制到;因此,模型不再脏了。save()finishSave()syncOriginal()$attributes$original
0赞 Adi 11/5/2023
哦,这很有趣,所以你的意思是或类似的重新加载,也可以使用吗?$this->defaultModel->fresh()
0赞 Olivier 11/5/2023
@Adi将返回从数据库加载的新模型对象;该对象不会是脏的(如果这是您的问题)。fresh()