-1

我有一个大约 25,000 行的 Excel 表。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();
    }
}

}

4

2 回答 2

1

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

于 2012-04-16T22:47:20.133 回答
1

您正在循环内创建一个新语句,但仅在循环结束后关闭最后一个语句。这意味着您实际上是在创建 25000 条语句,并且只关闭了一条而使 24999 条语句处于打开状态,这导致您耗尽资源并不感到惊讶。

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

编辑:

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

于 2012-04-16T23:20:46.067 回答