Java持久化内存泄漏

3

我有一张表格里面有100万行数据,我想获取全部数据。但是当我尝试使用JPA按照分页的方式获取所有数据时,出现了Java堆栈错误。你认为我可能漏掉了什么吗?有什么建议吗?

int counter = 0;
while (counter >= 0) {
   javax.persistence.EntityManager em = javax.persistence.Persistence
     .createEntityManagerFactory("MyPU")
     .createEntityManager();

   Query query = em.createQuery("select m from mytable m");
   java.util.Collection<MyEntity> data = query
          .setFirstResult(counter).setMaxResults(1000).getResultList();
   for(MyEntity yobj : data){
            System.out.println(obj);
   }
   counter += 1000;
   data.clear();
   em.clear();
   em.close();
}

你尝试过使用 -Xmx 增加堆大小的最大值吗?请参考:http://javahowto.blogspot.com/2006/06/6-common-errors-in-setting-java-heap.html - Teetrinker
2个回答

1

既然您已经使用本地SQL,那么您不能直接在SQL语句中指定LIMIT :counter, 1000(如果使用Oracle,则为ROWNUM BETWEEN :counter AND 1000)吗?


我正在使用MySQL,它可以指定限制,但是JPA不允许。 JPA提供了一种通过设置“firstResult”和“Max Result”来分页的机制,这很有效,但是当计数器达到250,000时,会抛出堆异常。 - user704006
2
是的,一些JPA实现会在内存中进行分页,而不是让数据库完成这项工作,这当然是荒谬的。EntityManager.createNativeQuery() 能够使用吗? - Lukas Eder
唯一的方法是使用本地查询进行分页,以防止内存泄漏。感谢大家,它有效了。 - user704006

0
请注意,在每次迭代时创建新的EntityManagerFactory实例,但不要关闭它。也许最好使用一个单独的工厂:
int counter = 0;
EntityManagerFactory emf = javax.persistence.Persistence.createEntityManagerFactory("MyPU");      
while (counter >= 0) {
    javax.persistence.EntityManager em = emf.createEntityManager(); 
    ...
}

我已经按照你的建议尝试实现了,但仍然无法释放内存。 - user704006

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接