- 导出数据到Excel,想必大家都有所了解,开发过程中也经常会遇到这种需求。假如导出的数据量不大还好说,数据量稍微大一点,就有可能会出现内存溢出。这个时候首先想到的可能就是调整服务器配置参数,但是数据量再大呢(千万级、亿级......),不管怎么调整配置参数,最后都避免不了内存溢出。那么,有没有一种方案能解决这个问题呢?答案是有的。
- 首先呢,我们需要先了解迭代器(生成器)这么个概念,这里我就不多说了,不了解的同学可以自行百度,或者参考:PHP yield简介 这篇文章。
- 其次,我们还需要了解 mysqli::query这个方法的第二个参数resultmode,一般默认值为MYSQLI_STORE_RESULT,这里我们需要用MYSQLI_USE_RESULT,对于这两个参数的区别,不了解的同学大家可以自行百度,或者参考: mysql中的MYSQLI_USE_RESULT和MYSQLI_STORE_RESULT模式分析 这篇文章。
好了,废话不多说了,直接上代码:
/**
* 迭代器
* Db类中的方法
* @param string $sql
* @return Generator
*/
public function query_use_result(string $sql)
{
$conn = $this->getConnection();
foreach ($conn->query($sql,MYSQLI_USE_RESULT) as $row )
{
yield $row;
}
}
/**
* 导出数据到Excel
* @param string $sql
*/
function output2excel(string $sql)
{
$filename = "订单";//文件名
set_time_limit(0);//不限制超时时间
header('Content-Type: application/vnd.ms-excel;charset=utf-8');
header('Content-Disposition: attachment;filename="' .$filename. '.csv"');
header('Cache-Control: max-age=0');
$fp = fopen('php://output', 'a');
fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF));//转码,防止乱码
foreach ( Db::Get()->query_use_result($sql) as $row )
{
//此处可以各种组装数据
fputcsv($fp, $row);//逐行写入csv文件
}
fclose($fp);//每生成一个文件关闭
}
$sql = "select * from order";
output2excel($sql);
- 此处代码写的比较简单,只是为了示意,实际开发中可以写的灵活一些,重要的是要了解整个思路。要注意的是,虽然导出到csv文件没有大小限制,但是Office展示的行数却是有限制的,所以如果数据量比较大,可以稍作改动,分成多文件导出。
网友评论