我们在处理庞大的数据集时遇到了问题。(它并不是那么大,但对我们来说这是巨大的,因为我们从未在使用Spring MVC + Oracle之前提取超过10万的数据)。
要求就是这样,我们需要每个月生成报告并将其邮寄给客户销售团队。报告生成为Excel文件,这是我们提取大量数据的地方。
我们使用Spring MVC和Oracle作为DB。当我在DB中运行查询时,它会在2秒内毫不费力地提取数据。但只有当我在Spring中通过SimpleJdbcCall或SP调用它时,我才会收到 Java堆空间错误。我将堆空间增加到2GB,但仍无用。我的系统配置是:
i3-4160 @ 3.6 GHz(四核?)/ 8GB RAM / Windows 7 Pro 64位。
请在我出错的地方帮助我,以及如何处理。粘贴下面的代码。
FlexiView.java (扩展StoredProcedure
)
package com.web.helper;
import java.util.List;
import java.util.Map;
import oracle.jdbc.OracleTypes;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.StoredProcedure;
import com.domain.ViewFormDO;
public class FlexiView extends StoredProcedure {
public FlexiView(JdbcTemplate jdbcTemplate, final String storedProc, ViewFormDO viewFormDO, int reportId){
super(jdbcTemplate, storedProc);
jdbcTemplate.setFetchSize(20000);
declareParameter(new SqlOutParameter("P_CUR", OracleTypes.CURSOR, new FlexiViewMapper(reportId, viewFormDO)));
declareParameter(new SqlParameter("P_AGENT_ID", OracleTypes.NUMBER));
this.compile();
}
@SuppressWarnings("unchecked")
public <T> List<T> executeStoredProc(final Map<String, Object> valueMap) {
System.out.println(">>"+valueMap.size());
// execute stored procedure
Map<String, Object> resultMap = super.execute(valueMap);
return (List<T>)resultMap.get("P_CUR");
}
}
CustomMapper
package com.web.helper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import org.springframework.jdbc.core.RowMapper;
import com.domain.ViewFormDO;
import com.domain.ViewFormGridDO;
public class FlexiViewMapper implements RowMapper<Object> {
int reportId = 0;
final SimpleDateFormat dtFormat = new SimpleDateFormat("dd-MM-yyyy");
ViewFormDO viewFormDO;
public FlexiViewMapper(int reportId, ViewFormDO viewFormDO){
this.reportId = reportId;
this.viewFormDO = viewFormDO;
}
@Override
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
ViewFormGridDO flexiActiveGridDet = new ViewFormGridDO();
if (reportId == 1001 || reportId == 1002) {
// Get data from DB and assign it in ViewFormGridDO Bean
}
return flexiActiveGridDet;
}
}
在DAO中调用此内容,就像这样
@Override
public List<ViewFormGridDO> getFlexiGuideEnqGridDet1(final ViewFormDO viewFormDO)
throws NsureException {
List<ViewFormGridDO> flexiGuideGridDetails = null;
final int reportId = viewFormDO.getFlexiTypeId() == GlobalNames.SCHEME_XXX ? 1002 : viewFormDO.getReportId();
LinkedHashMap<String, Object> valueMap = new LinkedHashMap<String, Object>();
valueMap.put("P_AGENT_ID", viewFormDO.getAgentId());
FlexiView flexiView = new FlexiView(jdbcTemplate, "PKG_XXXXX.prGetXXXXX", viewFormDO, reportId);
flexiGridDetails = flexiView.executeStoredProc(valueMap);
return flexiGridDetails;
}
最终更新:(a.k.a解决方案?)
我最终这样做了。我的Bean ViewFormDO有100多个字段,但我只需要20-30个字段。因此,豆类列表本身容易超过500MB标记。为避免这种情况,我更改了行映射器以在FlexiViewMapper中返回JSONObject而不是ViewFormDO。
尽管如此,生成7万卢比的excel记录证明会产生堆空间错误,为此,限制为5万卢比。更改了代码逻辑以消除不必要的值,并将数据从72万减少到20万。是的,生成了许多无用的组合。因此,经过所有这些优化后,即使我选择所有过滤器来生成报告,数据的数量也不会超过5 Lakh标记,并希望它会保持这种状态。我们已经给出了所有可能的方案!
答案 0 :(得分:2)
尝试将获取大小设置为较小的值。默认值为10.大于100的值很少提供显着的好处。您将其设置为20,000。 Oracle数据库JDBC驱动程序分配的内存量部分取决于获取大小;大的提取大小,更多的内存。将获取大小设置为更小的值很可能会解决您的问题。我建议将100作为开始。有关详细信息,请参阅此answer。