批处理进程在Spring + Hibernate + JPA中内存不足

时间:2011-10-07 14:54:05

标签: java hibernate spring jpa

我有一个批处理过程,它一个接一个地保存1000000条记录。每条记录都有自己的子表。我使用Spring 2.5.6,Hibernate和JPA来做到这一点。但一小时后,内存不足。有人可以告诉我我的申请中可能有什么问题吗?

以下是代码:

Public void processFeeds(List<Objects> feeds){

       for(Feed feed : feeds){
       Feed feed=getDAOMainFeedService().persist(feed);

       //Saving the child information
       if(feed.getID()>0)  {
           for(Address address : feeds.getAddress()){
               getDAOAddressService().persist(feed.getID,address);
        }

         for(PersonalInfo pi: feeds.getPersonalInfo){
               getDAOPIService().persist(feed.getID,pi);
        }
    }   
}

}

//service Class code:
public class MainFeedServiceDAOImpl extends JpaDaoSupport implements IVehYmmRevDAO
public Feed persist(Feed feed)
    {


        try
        {
            getJpaTemplate().persist(feed);
            feed=getJpaTemplate().merge(feed);
            getJpaTemplate().flush();

            return feed;
        }
        catch (Exception exception)
        {
            logger.error("Persit failed",
                    exception);
            throw new DatabaseServiceException(
                    "Persit failed", exception);
        }
    } 

}

其他DAO类也具有相同的MainFeedServiceDAOImpl实现,这些实现是使用Spring向上面的数据库服务层注入的。请提出一些建议。

2 个答案:

答案 0 :(得分:4)

程序内存不足的原因是因为您插入的每个对象都会保留在会话中。你需要偶尔清除它。

我以这种方式更改persist方法:

public void persist(List<Feed> feeds)
{
    int count = 0;
    try
    {
        for (Feed feed : feeds) {
            getJpaTemplate().persist(feed);
            if (count % 10000 == 0) {
                getJpaTemplate().flush();
                getJpaTemplate().getEntityManager().clear();
            }
            count++;
        }            
    }
    catch (Exception exception)
    {
        logger.error("Persist failed", exception);
        throw new DatabaseServiceException("Persist failed", exception);
    }
}

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/batch.html#batch-inserts

您可以对地址和个人信息对象使用相同的模式,但如果您拥有正确的映射和级联设置,则可能根本不需要这样做。

答案 1 :(得分:0)

虽然批量调用以保持提要是有帮助的,但它只会延迟OOME的发生。在您的系统需要处理更多数量的订阅源的那一天,它会在进入持久化阶段之前进入OOME。批处理逻辑也应该添加到要保留的提要的位置,进入系统,这样你就可以知道任何时候内存中存在的最大对象数。