使用Spring JDBC Template

时间:2017-09-19 13:24:46

标签: java spring oracle spring-mvc jdbc

我们在处理庞大的数据集时遇到了问题。(它并不是那么大,但对我们来说这是巨大的,因为我们从未在使用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标记,并希望它会保持这种状态。我们已经给出了所有可能的方案!

1 个答案:

答案 0 :(得分:2)

尝试将获取大小设置为较小的值。默认值为10.大于100的值很少提供显着的好处。您将其设置为20,000。 Oracle数据库JDBC驱动程序分配的内存量部分取决于获取大小;大的提取大小,更多的内存。将获取大小设置为更小的值很可能会解决您的问题。我建议将100作为开始。有关详细信息,请参阅此answer