我有一个批处理过程,它一个接一个地保存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向上面的数据库服务层注入的。请提出一些建议。
答案 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。批处理逻辑也应该添加到要保留的提要的位置,进入系统,这样你就可以知道任何时候内存中存在的最大对象数。