PHP如何批量更新MYSQL中的數據

        最近一直忙着做公司的項目,重構完前臺接着重構後臺,以至於沒有太多時間大理博客的內容,以後會定期更新自己的博客。

        在做公司後臺的時候,同事遇到了一個問題,就是產品規劃裏面有一個一鍵批量更新數據,在這個業務裏裏面涉及到了更新兩張數據表,那麼大家是不是會想到非常簡單,馬上上代碼

      

 $sql = "update newhouse_clicks set clicks=6,type=1,update_time=time() where is=$value['id']";

       其中數據表名爲newhouse_clicks,有四個字段,主鍵id,type(類型-整型)字段,clicks(點擊量-整型)字段,update_time(整型)字段

       這樣做確實沒有問題嗎?

       我們的業務是做互聯網房產的,比如說批量更新當前城市下的所有樓盤,比如說北京,打個比方1000條

       數據,那麼在業務裏裏面是不是就要這樣寫

$data = array(id=>1,id=>2,..........id=>1000);//省略數據
foreach($data as $key=>$value) {
    $sql = "update newhouse_clicks set clicks=6,type=1,update_time=time() where is=$value['id']";
}


        這樣在涉及到多張表*1000條數據,那麼會不會有很大的延時呢?

        結果是的,她這樣寫確實是導致了服務器的超時!

        大家如果熟悉JAVA等語言應該知道,JAVA會內部提供了批量更新sql的功能,那麼作爲世界上做好的語言PHP能不能做到呢?

        答案是可以滴!

        那麼我們學習一下批量更新的sql語句。

UPDATE newhouse_clicks
    SET clicks = CASE id
        WHEN 1 THEN 1000
        WHEN 2 THEN 2000
        WHEN 3 THEN 3000
    END
WHERE id IN (1,2,3)

       稍安勿躁,咱們詳解一下這條sql語句的意思:

       更新newhouse_clicks數據表中的clicks字段,當id=1是設置值爲1000,當id=2時設置值爲2000,當id=3時設置值爲3000


       那麼更新多個字段能不能做到呢?

       當然可以,貼代碼:

   

UPDATE newhouse_clicks
    SET clicks = CASE id
        WHEN 1 THEN 1000
        WHEN 2 THEN 2000
        WHEN 3 THEN 3000
    END,
    type = CASE id
        WHEN 1 THEN 1
        WHEN 2 THEN 6
        WHEN 3 THEN 8
    END
WHERE id IN (1,2,3)

        這條sql語句的含義就是更新newhouse_clicks數據表中的clicks字段,當id=1是設置值爲1000,當id=2時設置值爲2000,當id=3時設置值爲3000,更新type字段,當id=1時更新爲type字段爲1,當id=2時更新type字段爲6,當id=3時,更新type字段爲8

      
  那麼,世界上最好的語言PHP不就可以拼出來sql了嗎?

     

//查詢數據庫返回的數據格式
$newhouse_clicks = array(
      1 => 2,
      2 => 3,
      3 => 8,
      4 => 9,
  );
$ids = implode(',', array_keys($newhouse_clicks ));
$sql = "UPDATE newhouse_clicks SET clicks = CASE id ";
foreach ( $newhouse_clicks as $key => $value) {
    $sql .= sprintf("WHEN %d THEN %d ", $key, $value);
}
$sql .= "END WHERE id IN ($ids)";
echo $sql;

        大家查看一下是不是和咱們上面的sql語句是一樣的呀!

        那麼,咱們真是的數據是不是要比這複雜呀?

        肯定的

        看題,咱們通常在數據庫裏面取出來的數據格式是不是都是這樣的

//查詢數據庫返回的數據格式
$newhouse_clicks = array(
     1 => array('clicks'=>1,'type'=>1,'update_time'=>time()),
     2 => array('clicks'=>2,'type'=>2,'update_time'=>time()),
     3 => array('clicks'=>3,'type'=>3,'update_time'=>time()),
     4 => array('clicks'=>4,'type'=>4,'update_time'=>time()),
);
?>

        那麼,這種情況怎麼辦?

 

    
<?php
//查詢數據庫返回的數據格式
$newhouse_clicks = array(
    1 => array('clicks'=>1,'type'=>1,'update_time'=>time()),
    2 => array('clicks'=>2,'type'=>2,'update_time'=>time()),
    3 => array('clicks'=>3,'type'=>3,'update_time'=>time()),
    4 => array('clicks'=>4,'type'=>4,'update_time'=>time()),
);
    //獲取所有的id
    $newhouse_clicks_keys = array_keys($newhouse_clicks);
    //拼接批量更新sql語句
    $sql = "UPDATE newhouse_clicks SET ";
    //合成sql語句
    foreach ($newhouse_clicks[1] as $key => $value) {
        $sql .= "{$key} = CASE id ";
        foreach ($newhouse_clicks as $newhouse_clicks_key=>$newhouse_clicks_value) {

            $sql .= sprintf("WHEN %d THEN %d ", $newhouse_clicks_key, $newhouse_clicks_value[$key]);
        }
        $sql .= "END, ";
    }
    //把最後一個,去掉
    $sql = substr($sql, 0, strrpos($sql,',')); 
    //合併所有id
    $ids = implode(',', $newhouse_clicks_keys);
    //拼接sql
    $sql .= " WHERE ID IN ({$ids})";
    echo $sql;


        其實,寫了這麼一大堆,是不是就是爲了拼裝成mysql語句呀!


        大功告成!速度是不是像絲般順滑!

        老多程序員特別是初學者,很容易進入一個誤區,把在sql中取數據套在for循環裏面。這樣寫導致一個問題,就是嚴重的阻塞,現實生活中就有這樣一個例子:

        比如說,你在12層辦公,這是快遞員給你打電話讓你去樓下取快遞(總共12件),你去取快遞有兩種方式:

        1.拿到第一件快遞,跑回12層,放好後,接着去領取下一件快遞,放好12層後再接着去取下一件快遞。

        2.一次性把所有的快遞都拿到12層。

        大家一定都會選第二個方案吧,沒人會傻不拉幾的去跑12次才能拿完快遞的。

        計算機就是上述原理,在for循環裏面去資源取數據,就是類似第一種方案。批量取數據就是類似於第二種方案。(PS一下:不要以爲在mysql中取數據有這種問題,redis也會

有這種問題,要不然怎麼會有pipeline取批量數據呢,這一點在面試的時候我是經常當面試題去問的,絕對會成爲衡量一個人技術水平的標準)

        有問題歡迎大家探討,本人郵箱([email protected]),多謝~~~~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章