前次的多线程导出太过于马虎,未成结局,一直在记忆里环绕,仿佛一颗钉子深深扎在心头,时间鞭策我,为了群友更好摸鱼,我痛定思痛,重复考虑,决定重开一篇。
串行导出紧缩流程
- 生成表头
head
- 生成数据
dataList
- 根据
poi
,EasyPoi
,EasyExcel
等东西输出到ByteArrayOutputStream
-
ByteArrayOutputStream
写入ZipOutputStream
并紧缩 - 封闭流
调查上述流程,仔细考虑哪一步能变成并行,然后咱们从头梳理一下流程。
并行导出紧缩流程
- 生成表头
head
(串行) - 分页生成数据
dataList
(并行) - 循环分页成果集,根据
poi
,EasyPoi
,EasyExcel
等东西输出到ByteArrayOutputStream
(并行) - 循环分页成果集
flush
数据到ZipOutputStream
(串行) - 封闭流(串行)
从上面能够看出,导出的模型是,多线程读数据,单线程写数据到流。其间第2步和第3步能够兼并
有必要解说第1步,第4步,第5步为什么是串行
第1步和第5步不用多说,重点说第4步。简略而言便是数据写入到流的进程不是线程安全的,假如并行往流里写入数据,会发生原本线程 A 写的是,“张三,你胆敢摸鱼”,然后线程 B 写的是“老板娘!”,两个线程一起往流里边写入数据,成果输出了“张三,你胆敢摸老板娘!”这样的过错成果,所以第4步只能串行。这是个玩笑话,更多的时分会由于数据鸿沟过错导致反常。
明晰并行导出流程,下面咱们处理由于并行而引出的问题!
分页切开问题
咱们依照两个维度切开数据,文件和
sheet
,理想作用是根据导出数据总量得出文件数量fileNum
,根据sheetSize
核算每个文件sheet
数量sheetNum
,其间每一页sheet
查一次数据库所得,能够得出sheet
总数量 =fileNum
*sheetNum
,一起也是查询数据库的次数
文件和sheet
顺序问题
上图是3个文件,每个文件有两个sheet
(其间第3个文件只有一个sheet
,是由于第6个sheet
没有数据,没必要输出),sheetNo
的编号从1到5,对应SQL
的limit sheetNo, sheetSize
,然后文件也是要从file1,file2,file3
这样排序(文件名是url
编码了)
导出进程反常
导出会输出多个文件,每个文件多个
sheet
,咱们不能由于某一个sheet
,某个文件出错让整个导出进程失败,要把过错的原因写在sheet
返回客户端
三个或许呈现反常的当地
- 查询数据,或许呈现业务反常,数据库衔接反常
- 根据导出东西写入流,或许会呈现反常,概率不大
- 流提前封闭了,或许由于服务器资源不行,导致流反常封闭,神仙也救不了
呈现反常,想办法弥补,不是从头查询数据,应该是友好把过错信息写到sheet
,这样客户就能知道出错了,怎样出错了。
上图是三个文件,第一个文件sheet-1
的数据没问题,sheet-2
由于读数据过错,在sheet
输出load fial cause / by zore
,这样用户就知道哪里有问题。假如由于反常整个文件或许整个sheet
都不输出,客户底子没法知道导出的文件是否正常!
处理上面几个问题,导出功能根本明晰,但咱们是极客,怎样甘于平凡,所以我加了几个功能
导出中止
都多线程导出了,数据量肯定不小,几十万,几百万,几千万在那里导出,就看着进度条慢慢的涨,而你又等不下去了,把导出x
停了,换个查询条件继续导出。由此可见,导出中止有必要。本教程咱们根据future
实现中止导出线程,通过构建futureList
,与导出日志ID
绑定到map
,需求中止的时分从map
拿出futureList
,遍历futureList
,调用future.cancel()
。相关常识需求future
和java
中止线程,感兴趣的同学自行百度
断点续导
是的,有个名词叫断点续传,这两个功能是相同的,一个是能够暂停上传,一个是能够暂停下载。该计划需求导出文件到本地,根据RandomAccessFile
实现。本教程根据web
导出,实在是没有料呀,同学们感兴趣能够自己测验。
导出进度条
没得说,进度条能够是假的,但不能没有,根据redis
做个导出进度条没毛病吧!
github
项目放在github,首要核心DefaultedExporter
和EasyExcelExecutor
现已添加注释,不担心看不懂,clone
项目还需求自己补充repository
等