#java #hibernate #spring #jpa
#java #гибернация #весна #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 на уровень службы базы данных выше. Пожалуйста, дайте несколько предложений.
Комментарии:
1. Приведенный ниже ответ Джеймса Д.У. очень точен в вашем вопросе. Однако я рекомендую отказаться от Hibernate (или любого другого ORM) для пакетных заданий, даже если вы решите проблему с памятью, вы все равно столкнетесь с другими. Просто используйте JDBC.
Ответ №1:
Причина, по которой вашей программе не хватает памяти, заключается в том, что каждый вставляемый вами объект остается в вашем сеансе. Вам нужно время от времени его очищать.
Я бы изменил метод 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
Вы можете следовать тому же шаблону для своих адресов и объектов личной информации, хотя, если у вас установлены правильные сопоставления и каскады, вам может вообще не понадобиться выполнять этот бит.
Ответ №2:
Хотя пакетное выполнение вызовов для сохранения каналов помогло бы, это только задержало бы появление OOME. В тот день, когда вашей системе потребуется обработать большее количество каналов, она столкнется с OOME еще до того, как дойдет до стадии сохранения. Логика пакетной обработки также должна быть добавлена в том месте, где сохраняются каналы, входящие в вашу систему, чтобы вы знали максимальное количество объектов, которые присутствуют в памяти в любой момент времени.