laravel chunk 更新数据的坑

薄洪涛3年前PHP963

在一些情况下,我们需要对大批量的数据进行操作,如果这个时候我们使用foreach的话,很可能会遇到操作超时的情况。
Laravel框架中我们可以很方便的使用chunk方法来解决。

来看一个简单的例子:

$users = User::all();foreach ($users as $user) {
  $some_value = ($user->some_field > 0) ? 1 : 0;
  // 一些其他的逻辑
  $user->update(['some_other_field' => $some_value]);}

这段代码看起来并没有什么不对,但是当数据量很大的时候,情况就不那么乐观了,一方面是运行时间,再者要考虑数据存储时内存消耗完。

在Laravel中,应用chunk将数据分块的方法,可以很好的处理这种问题,下面是应用chunk的代码:

User::chunk(100, function ($users) {
  foreach ($users as $user) {
    $some_value = ($user->some_field > 0) ? 1 : 0;
    // might be more logic here
    $user->update(['some_other_field' => $some_value]);
  }});

这段代码是执行一个100条的数据进行更新,当执行完成后继续后面的另一百条数据……
也就是说他每次操作的是一个数据块而不是整个数据库。

User::chunk(100, function ($users) {
  foreach ($users as $user) {
    $some_value = ($user->some_field > 0) ? 1 : 0;
    // might be more logic here
    $user->update(['some_other_field' => $some_value]);
  }});

需要注意的是:当使用带筛选的条件的chunk时,如果是自更新,那么你会漏掉一些数据,接着看代码:

User::where('approved', 0)->chunk(100, function ($users) {
  foreach ($users as $user) {
    $user->update(['approved' => 1]);
  }});

如果要运行上面的代码,并不会有报错,但是where条件是筛选approved0user然后将approved的值跟新为1
在这个过程中,档第一数据库的数据被修改后,下一个数据块的数据将是在被修改后的数据中选出来的,这个时候数据变了,而page也加了1。所以执行结束后,只对数据中一半的数据进行了更新操作。

如果没有明白的话,我们来看一下chunk的底层实现。还以上面的代码为例,假如一共有400条数据,数据被按照100条进行分块处理。

page = 1: 最开始的时候page为1,选取1-100条数据进行处理;

page = 2: 这时候前一百数据的approved值全部为1,那么在次筛选的时候数据将从第101条开始,而这个时候的page=2,那么处理的数据将是第200-300之前的数据

之后依旧。

public function chunk($count, callable $callback){
    $results = $this->forPage($page = 1, $count)->get();

    while (count($results) > 0) {
        // On each chunk result set, we will pass them to the callback and then let the
        // developer take care of everything within the callback, which allows us to
        // keep the memory low for spinning through large result sets for working.
        if (call_user_func($callback, $results) === false) {
            return false;
        }

        $page++;

        $results = $this->forPage($page, $count)->get();
    }

    return true;}


作者:坚果牛奶
链接:https://www.jianshu.com/p/5dafd0d6e69a
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


相关文章

Yii2.0引入Ueditor

Yii2.0 引入Ueditor流程和其他框架不同必须引入Ueditor for Yii2.0,否则不能正常使用1,composer下载 composer require ...

Yii2.0搭建接口模块教程

Yii2.0搭建接口模块教程

最近我需要做一个大项目中的一个模块,考虑用前后端分离,所以想自己搭建一套基于Yii2.0的restful接口出来,本来的时候老大想让我用spring boot,无奈我太菜只会php.....教程开始:...

Elasticsearch按照日期聚合

Elasticsearch按照日期聚合

我们现在做的是医疗的业务,有个需求是这样的,查询出某位医生前七天的坐诊记录,并且,医生的坐诊记录是不连续的,这样就需要写一个dsl语句来实现es库的搜索首先我使用了es库中的聚合功能,按照日期去聚合,...

Yii2.0框架ActiveForm总结

首先引入ActiveForm和Html这里两个是很重要的<?php     use yii\bootstrap\ActiveForm; &nbs...

PHP程序猿食用RabbitMQ方法

消息队列是什么?“消息队列”是在消息的传输过程中保存消息的容器。“消息”是在两台计算机间传送的数据单位。消息可以非常简单,例如只包含文本字符串;也可以更复杂,可能包含嵌入对象。消息被发送到队列中。“消...

Yii2.0 jQuery(...).yiiActiveForm is not a function

Yii2.0 jQuery(...).yiiActiveForm is not a function

记一个常见的错误,如下图当我们在view中创建一个activeForm的时候,有时会报这种错误;通常情况下,是jquery重复引入导致的,因为你引入的jquey的版本跟yii2自带jquery版本冲突...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。