在Oracle数据库中保存数据时类java.lang.OutOfMemoryError

时间:2012-04-16 18:05:55

标签: java sql oracle11g

我有一张excel表,大约有25,000行。 excel工作表中的每一行也是我表格中的一行。我尝试做以下操作,它只是让我让内存超出绑定异常。我试图将batchSize从25改为50,100,500。它们都不起作用。谁能告诉我我做错了什么?改变JVM的堆大小对我来说不是一个选择。

public void saveForecast(List list) throws FinderException{
    final Session session = getCurrentSession();
    final int batchSize = 25;
    Connection con = null;
    PreparedStatement pstmt = null;
    Iterator iterator = list.iterator();
    int rowCount = list.size();
    String sqlStatement = "INSERT INTO DMD_VOL_UPLOAD (ORIGIN, DESTINATION, DAY_OF_WEEK, EFFECTIVE_DATE, DISCONTINUE_DATE, VOLUME)";
    sqlStatement += " VALUES(?, ?, ?, ?, ?, ?)";
    System.out.println(sqlStatement);
    System.out.println("Number of rows to be inserted: "+ rowCount);
    System.out.println("Starting time: "+new Date().toString());
    try{
        con = session.connection();
        for(int i=0; i<rowCount; i++){
            ForecastBatch forecastBatch = (ForecastBatch) iterator.next();              
            pstmt = con.prepareStatement(sqlStatement);             
            pstmt.setString(1, forecastBatch.getOrigin());
            pstmt.setString(2, forecastBatch.getDestination());
            pstmt.setInt(3, forecastBatch.getDayOfWeek());

            java.util.Date effJavaDate = forecastBatch.getEffectiveDate();
            java.sql.Date effSqlDate = new java.sql.Date(effJavaDate.getTime());                
            pstmt.setDate(4,  effSqlDate);              
            java.util.Date disJavaDate=forecastBatch.getDiscontinueDate();
            java.sql.Date disSqlDate =  new java.sql.Date(disJavaDate.getTime());   

            pstmt.setDate(5, disSqlDate);               
            pstmt.setInt(6, forecastBatch.getVolumeSum());

            pstmt.addBatch();
            if(i % batchSize == 0){
                pstmt.executeBatch();
                session.flush();
                session.clear();
            }
        }
        pstmt.executeBatch();
        pstmt.close();
        System.out.println("Ending Time: "+ new Date().toString());
    }catch(SQLException e){
        e.printStackTrace();
        throw new FinderException(e);
    }
    finally{
        HibernateUtil.closeSession();
    }
}

}

2 个答案:

答案 0 :(得分:1)

您的主要问题似乎是您正在为每一行重新准备声明。你应该准备一次声明。这可能会导致消耗大量内存。

答案 1 :(得分:1)

您正在循环中创建一个新语句,但只在循环结束后关闭最后一个语句。这意味着您实际上创建了25000个语句并且只关闭了一个语句,并且打开了24999个语句,我并不感到惊讶,这会导致资源耗尽。

此外,您没有正确使用批处理语句(您必须创建一次语句,然后设置参数,调用addBatch,设置更多参数,再次调用addBatch,等等,然后如果要提交批处理中的所有值,请调用executeBatch。

编辑:

您可能会通过在for循环之前移动prepareStatement调用来解决此问题,我也不认为调用会话刷新/清除是必要的。