laravel 队列中处理 excel 上传
余温
2020年12月03日 16时38分
php
--laravel 队列 处理任务官方文档就基本很清晰了
看代码就比较清晰
<?php
namespace App\Jobs;
/**
* 处理上传文件
* Class Excel
* @package App\Jobs
*/
class Excel implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 2; //队列错误重试次数
public $timeout = 60 * 60 * 5;//队列执行超时时间(秒)
/**
* 初始化的时候设置参数为全局变量
*/
public function __construct($fileUrl)
{
$this->fileUrl = $fileUrl;
}
/**
* Execute the job.
*/
public function handle()
{
//任务执行过程 导入excel
\Excel::import(new ImportServiceExcel($this->fileUrl), $this->fileUrl);
}
/**
* 任务失败处理
* @param Exception $exception
*/
public function failed(\Exception $exception)
{
self::unsuccessful($this->userInfo['id'],$exception);
}
}
使用 horizon 管理队列
这个也是官方文档就很清晰了
这个我使用的时候无法按照官方给的放假进行授权然后就是用了 www-authenticate认证 方法 添加一个中间件就 OK 这个也是比较简单的
namespace App\Http\Middleware;
use Closure;
class HorizonBasicAuth
{
/**
* 队列监控验证
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->getUser() != 'user' || $request->getPassword() != 'password') {
$headers = array('WWW-Authenticate' => 'Basic');
return response('Unauthorized', 401, $headers);
}
return $next($request);
}
}
excel 导入
excel 导入是用的是 laravel-excel 照例还是先贴 文档地址 一般来说看文档能解决大部分问题 因为每次导入的 excel 数量还是比较大 一次导入的话很大的可能就是内存超出限制
使用队列导入 excel 主要原因还是 excel 数据量太大 导入需要时间太长 这样可以让用户不需要等待 也可以使用异步的方式
使用这个的分块导入还是比较好处理
<?php
namespace App\Imports;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;//去除表头
//新增
use Maatwebsite\Excel\Concerns\WithChunkReading;
class ImportService implements ToCollection, WithChunkReading, WithHeadingRow
{
private $batchSize = 500;
private $task_id = 0;
private $fileUrl = '';
private $num = 0;
private $data_array =[];
/**
* @param int $task_id
* @param string $fileUrl
*/
public function __construct(int $task_id,$fileUrl='')
{
$this->task_id = $task_id;
$this->fileUrl = $fileUrl;
}
public function collection(Collection $rows)
{
$arr = array_chunk($rows->toArray(), $this->batchSize);
foreach ($arr as $vo) {
$this->createData($vo);
$this->num += $this->batchSize;
//$this->data_array 批量添加到数据库
$this->data_array = [];
}
}
// 每次读取多少条数据 可以根据自己的需求设置
public function chunkSize(): int
{
return 5000;
}
}
基本上这样就完美的搞定了这个功能
写在最后
第一个坑
一开是我是使用的 http 模仿的异步 大概就是这样
<?php
$ch = curl_init();
$curl_opt = array(
CURLOPT_URL, 'http://www.example.com/doRequest.php'
CURLOPT_RETURNTRANSFER,1,
CURLOPT_TIMEOUT,1
);
curl_setopt_array($ch, $curl_opt);
curl_exec($ch);
curl_close($ch);
?>
这个方法使用中最严重的问题就是不稳定 有时候会导致不去执行
第二个坑
再就是 读 excel 的时候 我是每一行去数据库判断一个有没有重复值再去插入 这样就导致运行速度非常之慢 十万的数据就要执行几十分钟
目前的解决方案是 读取 excel 之后没五百条批量插入一次数据库 放弃判断重复值 在执行逻辑的时候判断是否重复 这样可以大大提升写入速度 大概四十几万数据读取写入只需要 三五分钟,效率几十倍的提升
这个期间我也使用过 xlswrite 读取速度相较于 laravel-excel 提升很多,但是问题就是安装的话没有 larvel-excel 好安装 毕竟是要安装 php 扩展。而且只支持 xlsx (别的格式可能是我没有发现使用方法)
最后最重要的一句 这个的最大瓶颈还是在数据库 读取excel 的速度其实影响并不是很大
上一篇:
限制访问次数
请登陆后评论
{{vo.time}} 回复