[Laravel-Excel中文文档] 使用queued队列实现后端分批次导出大量数据

Song222 次浏览0个评论2022年03月21日
如果我们导出数据过大,最好使用queued进行导出数据;避免excel导出占满服务器内存,实现分批次导出数据。

如上所说我们希望所有Laraveld队列导出数据;接下来我们先看实际使用Demo再看文档。

实战使用Demo

asda


官方文档翻译

如果您正在处理大量数据,使用queue队列处理进程可能更明智。 

我们提供以下导出类:

namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}

现在调用->queue()就可以简单实现队列方法。

(new InvoicesExport)->queue(invoices.xlsx);

return back()->withSuccess(Export started!);

在队列中将会使用chunck分块查询并且将多个jobs链接起来。这些job将以正确的顺序执行,并且只有在之前的作业都没有失败的情况下才会执行。

隐式导出队列

您还可以将导出隐式标记为排队导出。你可以使用 Laravel 的ShouldQueue协议来实现。

namespace App\Exports;

use App\Invoice;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class InvoicesExport implements FromQuery, ShouldQueue
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}

在您的控制器中,您现在可以调用普通->store()方法。根据ShouldQueue协议的存在,导出将排队执行。

(new InvoicesExport)->store(invoices.xlsx);

追加jobs

queue()方法返回 Laravel 的PendingDispatch. 这意味着您可以链接额外的jobs,这些job将被添加到队列的末尾,并且只有在所有导出作业都正确执行时才执行。

(new InvoicesExport)->queue(invoices.xlsx)->chain([
    new NotifyUserOfCompletedExport(request()->user()),
]);
namespace App\Jobs;

use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\SerializesModels;

class NotifyUserOfCompletedExport implements ShouldQueue
{
    use Queueable, SerializesModels;
    
    public $user;
    
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function handle()
    {
        $this->user->notify(new ExportReady());
    }
}

处理queued导出中的失败

在对导出进行排队时,您可能需要一种处理失败导出的方法。您可以在您的导出类添加failed方法来实现。


use Throwable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class UsersExport implements FromQuery, WithHeadings
{   
    public function failed(Throwable $exception): void
    {
        // handle failed export
    }
}

自定义队列

因为PendingDispatch是返回的,所以我们也可以改变应该使用的队列。

对于 Laravel 8+:

(new InvoicesExport)->queue(invoices.xlsx)->onQueue(exports);

对于旧版本的 Laravel:

(new InvoicesExport)->queue(invoices.xlsx)->allOnQueue(exports);

多服务器设置

如果您正在处理多服务器设置(例如使用负载平衡器),您可能希望确保用于存储每个数据块的临时文件对于每个作业都是相同的。您可以通过在 config.xml 中配置远程临时文件来实现此目的。

config/excel.php

temporary_files => [
    remote_disk => s3,
],

Job中间件

如果您使用的是 Laravel 6,作业中间件 (打开新窗口)可以使用以下middleware方法附加到导出类:

namespace App\Exports;

use App\Jobs\Middleware\RateLimited;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class ExportClass implements FromQuery
{
    use Exportable;
    
    public function middleware()
    {
        return [new RateLimited];
    }

    public function query()
    {
        // ...
    }
}

本地化排队导出

如果你想本地化你的队列导出,你应该HasLocalePreference在你的导出上实现协议:

namespace App\Exports;

use Illuminate\Contracts\Translation\HasLocalePreference;
use Maatwebsite\Excel\Concerns\Exportable;

class ExportClass implements HasLocalePreference
{
    use Exportable;
    
    public function __construct(string $locale)
    {
        $this->locale = $locale;
    }
    
    public function preferredLocale()
    {
        return $this->locale;
    }
}

自定义查询大小

排队的可导出文件以块的形式处理;每个块都是由QueuedWriter. 对于实现FromQuery问题的可导出文件,作业数是通过除以$query->count()块大小来计算的。

何时使用

根据query()方法的实现(例如使用groupBy子句时),前面提到的计算可能不正确。

如果是这种情况,您应该使用WithCustomQuerySize关注点来提供查询大小的自定义计算。

提交评论

请登录后评论

用户评论

    当前暂无评价,快来发表您的观点吧...

更多相关好文