我正在尝试使用Apache Poi将数据库表中的数据写入Xlsx文件。首先,我使用XSSFWorkbook进行了尝试。我想写几乎100万个具有100个属性的元组。所以我在使用XSSFWorkbook时遇到OutOfMemory错误,因为它在写入之前将整个数据加载到内存中。
所以我尝试使用SXSSFWorkbook。它支持流传输,因此内存使用率没有问题。当有单个客户端请求时,它非常有用。确切地说,响应花费了将近1分30秒(对于单个客户端)。我在机器上使用的是Apache Tomcat 8.5.32服务器。
我从apache文档中了解到SXSSFWorkbook仅在内存中保留指定数量的行,并将其他行写入临时文件。
我的代码分为两部分。
SXSSFWorkbook wb = new SXSSFWorkbook(100);
Sheet sh = wb.createSheet();
String name = UUID.randomUUID().toString().replace("-", "") + ".xlsx";
try {
String sql = "select * from users";
ResultSet rs = stmt.executeQuery(sql);
System.out.println("Query finished");
int i=1;
while(rs.next()) {
User user = getUserByRS(rs);
Row row = sh.createRow(i++);
Cell cell1 = row.createCell(0);
cell1.setCellValue(user.getUid());
for(int j=1;j<100;j+=2) {
Cell cell2 = row.createCell(j);
cell2.setCellValue(user.getUsername());
Cell cell3 = row.createCell(j+1);
cell3.setCellValue(user.getText());
}
if(i%40000==0) {
Date mydate = new Date();
System.out.println( (i/4000) + "% completed" + " System date : "+ mydate.toString());
out.println( (i/4000) + "% completed" + " System date : "+ mydate.toString());
out.println(Runtime.getRuntime().totalMemory() + " " + Runtime.getRuntime().freeMemory());
System.gc();
}
}
这是我代码的第一部分。此代码从数据库获取数据(SQL查询中已处理了来自数据库的数据流。因此这里没有内存问题)并将其写入SXXFSWorkbook,后者将数据写入中间的临时磁盘文件。如果有一个客户端请求,这部分代码将花费近40秒,而如果有6-8个客户端请求(一起)则将花费5-6分钟。为什么?。
来到我的代码的第二部分。
FileOutputStream out1 = new FileOutputStream(new File("/Users/test/Desktop/reports/" + name));
wb.write(out1);
out1.close();
这是代码的一部分,其中中间磁盘文件中的数据被写入到我的响应文件的输出流中。如果是单个文件,则将花费近40秒,如果是6-8个客户端请求,则将花费大约10-11分钟。为什么?
此外,速度随内存中加载的行数而变化。例如,在100行的情况下,为6-8个客户请求提供服务大约需要20分钟,而在10行的情况下,相同的则大约需要12-15分钟。为什么?
此外,所有请求的响应文件将同时写入。由于服务器将每个请求作为单独的线程处理,为什么会发生这种情况?