參考鏈接:http://www.itdecent.cn/p/5dafd0d6e69a
在一些情況下,我們需要對大批量的數(shù)據(jù)進行操作,如果這個時候我們使用foreach的話,很可能會遇到操作超時的情況。
在Laravel框架中我們可以很方便的使用chunk方法來解決。
來看一個簡單的例子:
$users=User::all();foreach($usersas$user){$some_value=($user->some_field>0)?1:0;// 一些其他的邏輯$user->update(['some_other_field'=>$some_value]);}
這段代碼看起來并沒有什么不對,但是當數(shù)據(jù)量很大的時候,情況就不那么樂觀了,一方面是運行時間,再者要考慮數(shù)據(jù)存儲時內(nèi)存消耗完。
在Laravel中,應(yīng)用chunk將數(shù)據(jù)分塊的方法,可以很好的處理這種問題,下面是應(yīng)用chunk的代碼:
User::chunk(100,function($users){foreach($usersas$user){$some_value=($user->some_field>0)?1:0;// might be more logic here$user->update(['some_other_field'=>$some_value]);}});
這段代碼是執(zhí)行一個100條的數(shù)據(jù)進行更新,當執(zhí)行完成后繼續(xù)后面的另一百條數(shù)據(jù)……
也就是說他每次操作的是一個數(shù)據(jù)塊而不是整個數(shù)據(jù)庫。
User::chunk(100,function($users){foreach($usersas$user){$some_value=($user->some_field>0)?1:0;// might be more logic here$user->update(['some_other_field'=>$some_value]);}});
需要注意的是:當使用帶篩選的條件的chunk時,如果是自更新,那么你會漏掉一些數(shù)據(jù),接著看代碼:
User::where('approved',0)->chunk(100,function($users){foreach($usersas$user){$user->update(['approved'=>1]);}});
如果要運行上面的代碼,并不會有報錯,但是where條件是篩選approved為0的user然后將approved的值跟新為1。
在這個過程中,檔第一數(shù)據(jù)庫的數(shù)據(jù)被修改后,下一個數(shù)據(jù)塊的數(shù)據(jù)將是在被修改后的數(shù)據(jù)中選出來的,這個時候數(shù)據(jù)變了,而page也加了1。所以執(zhí)行結(jié)束后,只對數(shù)據(jù)中一半的數(shù)據(jù)進行了更新操作。
如果沒有明白的話,我們來看一下chunk的底層實現(xiàn)。還以上面的代碼為例,假如一共有400條數(shù)據(jù),數(shù)據(jù)被按照100條進行分塊處理。
page = 1: 最開始的時候page為1,選取1-100條數(shù)據(jù)進行處理;
page = 2: 這時候前一百數(shù)據(jù)的approved值全部為1,那么在次篩選的時候數(shù)據(jù)將從第101條開始,而這個時候的page=2,那么處理的數(shù)據(jù)將是第200-300之前的數(shù)據(jù)
之后依舊。
publicfunctionchunk($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){returnfalse;}$page++;$results=$this->forPage($page,$count)->get();}returntrue;}