2011-05-26 70 views
1

在我的应用程序中,我使用CSVReader & hibernate将大量实体(如1 500 000或更多)从csv文件导入数据库。代码如下所示:在保存大量实体时,Hibernate会导致内存不足异常

 Session session = headerdao.getSessionFactory().openSession(); 
     Transaction tx = session.beginTransaction(); 

     int count = 0; 
     String[] nextLine; 

     while ((nextLine = reader.readNext()) != null) { 
      try { 

       if (nextLine.length == 23 
         && Integer.parseInt(nextLine[0]) > lastIdInDB) { 
        JournalHeader current = parseJournalHeader(nextLine); 
        current.setChain(chain); 
        session.save(current); 
        count++; 
        if (count % 100 == 0) { 
         session.flush(); 
         tx.commit(); 
         session.clear(); 
         tx.begin(); 
        } 
        if (count % 10000 == 0) { 
         LOG.info(count); 
        } 

       } 

      } catch (NumberFormatException e) { 
       e.printStackTrace(); 
      } catch (ParseException e) { 
       e.printStackTrace(); 
      } 

     } 
     tx.commit(); 
     session.close(); 

对于足够大的文件(某处大约700 000行),出现内存异常(堆空间)。

看来,这个问题在某种程度上与hibernate相关,因为如果我只是注释行session.save(current);它运行良好。如果未注释,任务管理器将显示javaw的内存使用量不断增加,然后在某些时候解析会变得非常慢并且崩溃。

parseJournalHeader()没有什么特别之处,它只是解析基于csv阅读器给出的String[]的实体。

+1

你看起来像是在用清理会话的方式做正确的事情,应该清理内存问题......一个潜在的可能是第二级缓存,它不会被session.clear清空。它的设置是什么......也许设置CacheMode.GET? – sMoZely 2011-05-26 10:13:31

+1

无状态会话在这里可能很有用。在这里阅读无状态会话的限制:http://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/StatelessSession.html,如果它们在您的用例中不是问题,请尝试使用它(通过sessionFactory.openStatelessSession()) – 2011-05-26 10:25:25

回答

1

会话实际上将缓存中的对象保留下来。你正在做正确的事情来处理一级缓存。但是有更多的东西阻止垃圾收集的发生。

尝试改用StatelessSession。

+0

我尝试使用StatelessSession但具有相同的结果。使用Eclipse内存分析器检查转储告诉我,6个“com.mysql.jdbc.JDBC4PreparedStatement”是最大的泄漏嫌疑人。它们几乎消耗了所有的内存。这是否说明了有关问题的一些情况? – northernd 2011-05-26 11:24:40

+0

看来问题在某种程度上与c3p0缓存语句有关。我从hibernate.cfg中删除了c3p0配置,并摆脱了内存问题。我会尽力进一步调查 – northernd 2011-05-26 11:45:58