2011-05-26 69 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