最近產品出了個需求,要求:php
在後臺管理系統導入10~50w左右的數據到系統,經過excel上傳,能夠非實時,模板爲下圖
做爲程序員,第一反應腦海裏應該出現瞭如下幾個關鍵字mysql
很好,其實主要的解決方案的確圍繞在這幾個問題,其實現實問題中有不少的解決方案,好比可否經過csv,naviecat導、load data、寫入一個 sql 文件,而後 mysql source執行等等。那麼接下來咱們應該按What - Why - How來對應選擇方案laravel
可是在實際場景中,咱們應該把需求更加具體化,好比git
PHPExcel+Mysql Update,簡單粗暴的方案,讀一行(excel)寫一行(update),可是必須在後臺常駐內存執行,不然會超時、嚴重影響業務進行。我這裏經過thinkphp5的命令行+定時任務執行,innodb是行鎖,要注意更新內容的範圍程序員
PHP 高性能 Excel 擴展VtifulKernelExcel + Mysql update(case when),使用遊標模式逐行讀取excel單元格,然我這裏循環excel,而後大概1000條更新一次,拼接後sql的語句相似如下:github
UPDATE `mytable` SET `name` = CASE WHEN `title` = 'My title' THEN 'My Name 2' WHEN `title` = 'Another title' THEN 'Another Name 2' ELSE `name` END, `date` = CASE WHEN `title` = 'My title' THEN 'My date 2' WHEN `title` = 'Another title' THEN 'Another date 2' ELSE `date` END WHERE `title` IN ('My title','Another title')
直接上業務代碼sql
//先使用phpexcel獲取總行數,Vtiful沒找到這個功能 $objReader = \PHPExcel_IOFactory::createReader('Excel2007'); $objReader->setReadDataOnly(true); try { // 載入文件 $objPHPExcel = $objReader->load('tutorial.xlsx'); } catch (\Exception $e) { throw new \Exception("載入文件失敗"); } // 獲取表中的第一個工做表 $currentSheet = $objPHPExcel->getSheet(0); // 獲取總行數 $allRow = (int)$currentSheet->getHighestRow(); $excel = new \Vtiful\Kernel\Excel($config); $data = $excel->openFile('tutorial.xlsx')->openSheet(); $data->nextRow();//手動跳過第一行 //算出每多少更新一次 $commit_every = 1000; $commit_k = ceil($allRow / $commit_every); $arr_commit = []; for ($i = 1; $i <= $commit_k; $i++) { $arr_commit[] = $i * $commit_every; } if (end($arr_commit) < $allRow) { $arr_commit[] = $allRow - 1;//由於跳過了第一條 } // while ($rowData = $excel->nextRow()) { //todo 非數字設置爲0 //todo 評分三也要 //todo 導入評分行數 if (!is_numeric($rowData[0])) { continue; } if (!is_numeric($rowData[1])) { $rowData[1] = 0; } if (!is_numeric($rowData[2])) { $rowData[2] = 0; } if (!is_numeric($rowData[3])) { $rowData[3] = 0; } $upd[] = [ 'id' => $rowData[0],//主鍵 'a' => (int)$rowData[1], 'b' => (int)$rowData[2], 'c' => (int)$rowData[3], ]; if (in_array($line, $arr_commit)) { $this->updateBatch('table', $upd); unset($upd); } } public function updateBatch($tableName = "", $multipleData = array()) { if ($tableName && !empty($multipleData)) { // column or fields to update $updateColumn = array_keys($multipleData[0]); $referenceColumn = $updateColumn[0]; //e.g id unset($updateColumn[0]); $whereIn = ""; $q = "UPDATE " . $tableName . " SET "; foreach ($updateColumn as $uColumn) { $q .= $uColumn . " = CASE "; foreach ($multipleData as $data) { $q .= "WHEN " . $referenceColumn . " = " . $data[$referenceColumn] . " THEN '" . $data[$uColumn] . "' "; } $q .= "ELSE " . $uColumn . " END, "; } foreach ($multipleData as $data) { $whereIn .= "'" . $data[$referenceColumn] . "', "; } $q = rtrim($q, ", ") . " WHERE " . $referenceColumn . " IN (" . rtrim($whereIn, ', ') . ")"; // Update return Db::execute(Db::raw($q)); } else { return false; } }
到這裏基本就結束了,文中參考到的mysql update、xlxs擴展(若是項目不容許或者麻煩的話不適用也能夠的)
https://stackoverflow.com/que...
https://github.com/viest/php-...thinkphp