把稳不要在一个模型实例里面做多次更新,会导致部分重复数据不再更新,精确的办法该当是先查询后更新或者利用模型类的update方法更新。
只是解释了问题,但没有阐明为什么,以是就没把稳,导致涌现这个问题。
在Model.php模型save方法末了大概1214行

// 重新记录原始数据$this->origin = $this->data;
origin这个属性记录了原始数据,不管是更新还是写入,都把操作的字段给记录下来了。 而在1105行调用的方法
// 获取有更新的数据$data = $this->getChangedData();
1266行
//force逼迫更新就不会比对,这个是文档没有提到的if ($this->force) { $data = $this->data;} else { //比对了两个数组的差别 $data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) { if ((empty($a) || empty($b)) && $a !== $b) { return 1; } return is_object($a) || $a != $b ? 1 : 0; }); }
可以看到如果$this->force为false时就要判断上次记录的字段和这次更新的字段有没有交集,只会更新上次没有记录的字段,因此在循环中save更新只能更新一次,由于已经记录了更新的字段,就不会再更新了。
为什么用模型update方法就不会涌现这个问题呢?由于模型的update方法是每次调用都会重新实例化一个工具,自然就没有记录原始数据了。
public static function update($data = [], $where = [], $field = null){ $model = new static();//实例化了新的工具来调用 if (!empty($field)) { $model->allowField($field); } $result = $model->isUpdate(true)->save($data, $where); return $model; }
怎么办理?
办理办法也很大略,手册也提到了,有三种方法:
官方手册提到的,先查询,再更新。如果查询出来是列表,就循环用item去调用save。也是官方的,调用update方法更新。但是一定要把稳,用模型的update方法,不要用query类的update方法。,鉴别方法便是不要调用where,更新参数通过数组传到update方法。通过query类update更新虽然能够成功更新,但是就不能自动完成了,很多配置在模型的数据转换会失落效。在调用更新之前链式调用->force()方法即可问题二:想要软删除却变成真删除了开拓中配置好了软删除,但是利用的时候却一贯是真删除。代码如下:
//删除剩下未审核的$delete_res = ProjectMakeWorkflowCheckDetail::where('project_workflow_check_id',$params['project_workflow_check_id'])->where('status','0')->delete();
看起来挺正常的,便是没有软删除。缘故原由:
由于调用了where方法,此时工具返回的便是Query类,不再是模型的Model类,所往后面调用delete也便是Query类的delete方法了。而Query类是不支持软删除的。以是就失落效了。办理办法:先查询出列表,再循环利用item去调用delete。不调用where,直接调用destroy,把查询参数用数组传进去。事实上两种办法实质上都是一样的。destory方法里也是先查询出来,然后循环调用delete。总结:thinkphp5的模型和数据库Query类有很多方法同等,导致常常调用的方法不是预期的方法。同一个模型不要调用多次写操作。调用了where查询后不要立时调用写操作,要查询出数据再用返回的工具调用写操作。看手册要负责。