laravel实现大数据csv导出(加qq群:342430957)

本文探讨了在Laravel框架下处理大数据导出时遇到的问题及解决方案,包括避免使用toArray()方法防止内存泄露,采用chunk()方法分批处理数据,以及通过队列任务实现大数据导出的异步处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先说明几点:

1,excel格式的文件最大支持100万的数据,所以不考虑使用excel格式
2,laravel的toArray()方法有内存泄露,所以大量数据导出不能使用.
3,当然要使用chunk方法查询数据,然后写到文件中

关于toArray()方法内存泄露排查

chunk()方法的代码块如下(chunk中按理是不用unset的,会自动释放):

query−>chunk(1000,function(query->chunk(1000, function (query>chunk(1000,function(data) use (&$firstWrite, $fp) {
Log::info(“开始:”.memory_get_usage());
$data = data−>toArray();Log::info("结束:".memorygetusage());unset(data->toArray(); Log::info("结束:".memory_get_usage()); unset(data>toArray();Log::info(":".memorygetusage());unset(data);
Log::info(“usnet 结束:”.memory_get_usage());
});

在将一个“组块”的 Eloquent 模型转为数组的时候$data = $data->toArray();内存增加了很多.最后unset的时候又没有释放回初始值.实际上chunk中是不需要unset释放的.
解决

使用
DB::table(“xxx”)->->orderBy(xx)->chunk(xx);方式查询数据,查询结果在使用data=jsondecode(jsonencode(data = json_decode(json_encode(data=jsondecode(jsonencode(data), true);转换成数组,每次chunk执行进去,内存都是一样的,内部也不需要unset.

大数据导出最后做的方案

因为数据量大,所以我的做法是,小量数据导出就直接发送给用户.大数据导出,走队列任务,然后做一个报表管理,用户可以查看进度和完成后下载.

在浏览器中直接返回文件和后台写入文件

函数基本使用
fp=fopen("文件路径/文件名","a");//a表示追加模式fwrite(fp = fopen("文件路径/文件名", "a"); //a表示追加模式 fwrite(fp=fopen("/","a");//afwrite(fp, chr(0xEF).chr(0xBB).chr(0xBF)); // 添加 BOM,不然excel打开csv是乱码
在chunk的闭包中写数据: fputcsv($fp, array);fclose(array); fclose(array);fclose(fp);
在队列中导出

fp=fopen(storagepath(′app/public/exports′)."/".fp = fopen(storage_path('app/public/exports')."/".fp=fopen(storagepath(app/public/exports)."/".report->name, “a”);
fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF)); // 添加 BOM
$firstWrite = true;
$query = expoter−>customQuery(expoter->customQuery(expoter>customQuery(query);
query−>orderBy(query->orderBy(query>orderBy(tableName.".id")->chunk(1000, function (KaTeX parse error: Expected 'EOF', got '&' at position 12: data) use (&̲firstWrite, $fp, $expoter) {
data=jsondecode(jsonencode(data = json_decode(json_encode(data=jsondecode(jsonencode(data), true);

            $data = $expoter->customData($data);
            //有一些列总是不导出,如icon,image,images
            $data = ExportUtils::removeInvalids($data);
            //写列名
            if ($firstWrite) {
                $columnNames = [];
                //获取列名
                foreach ($data[0] as $key => $value) {
                    $columnNames[] = admin_translate($key, "coupon");
                }
                fputcsv($fp, $columnNames);
                $firstWrite = false;
            }
            foreach ($data as $item) {
                fputcsv($fp, $item);
            }
        });

        fclose($fp);

在浏览器中返回数据

response=newStreamedResponse(null,200,[′Content−Type′=>′text/csv′,′Content−Disposition′=>′attachment;filename="′.response = new StreamedResponse(null, 200, [ 'Content-Type' => 'text/csv', 'Content-Disposition' => 'attachment; filename="'.response=newStreamedResponse(null,200,[ContentType=>text/csv,ContentDisposition=>attachment;filename=".fileName.’"’,
]);
response−>setCallback(function()use(response->setCallback(function () use (response>setCallback(function()use(query, $tableName) {
out=fopen(′php://output′,′w′);fwrite(out = fopen('php://output', 'w'); fwrite(out=fopen(php://output,w);fwrite(out, chr(0xEF).chr(0xBB).chr(0xBF)); // 添加 BOM

            $firstWrite = true;

            $query = $this->customQuery($query);

            $query->orderBy($tableName.".id")->chunk(500, function ($data) use (&$firstWrite, $out) {

                $data = json_decode(json_encode($data), true);

                $data = $this->customData($data);
                //有一些列总是不导出,如icon,image,images
                $data = ExportUtils::removeInvalids($data);
                //写列名
                if ($firstWrite) {
                    $columnNames = [];
                    //获取列名
                    foreach ($data[0] as $key => $value) {
                        $columnNames[] = admin_translate($key, "coupon");
                    }
                    fputcsv($out, $columnNames);
                    $firstWrite = false;
                }
                foreach ($data as $item) {
                    fputcsv($out, $item);
                }
            });

            fclose($out);
        });
        $response->send();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值