Я использую Grails 1.1 beta2. Мне нужно импортировать большой объем данных в мое приложение Grails. Если я неоднократно создаю экземпляр класса домена Grails, а затем сохраняю его, производительность будет недопустимо низкой. Возьмем, к примеру, импорт людей из телефонной книги:
for (each person in legacy phone book) {
// Construct new Grails domain class from legacy phone book person
Person person = new Person(...)
person.save()
}
Это оказывается мучительно медленным. Кто-то из списка рассылки Grails предлагает пакетное сохранение в транзакции. Итак, теперь у меня есть:
List batch = new ArrayList()
for (each person in legacy phone book) {
// Construct new Grails domain class from legacy phone book person
Person person = new Person(...)
batch.add(person)
if (batch.size() > 500) {
Person.withTransaction {
for (Person p: batch)
p.save()
batch.clear()
}
}
}
// Save any remaining
for (Person p: batch)
p.save()
Это должно работать быстрее, по крайней мере, на начальном этапе. Каждая транзакция сохраняет 500 записей. Со временем транзакции занимают все больше и больше времени. Первые несколько транзакций занимают около 5 секунд, затем оттуда просто ползет. После примерно 100 транзакций каждая занимает более минуты, что опять-таки недопустимо. Хуже всего то, что со временем у Grails закончится куча памяти Java. Я могу увеличить размер кучи JVM, но это только задерживает исключение OutOfMemoryError
.
Есть идеи, почему это так? Как будто там какой-то внутренний ресурс не выпускается. Производительность ухудшается, память удерживается, а затем, в конце концов, системе не хватает памяти.
Согласно документации Grails *1013*, withTransaction
передает замыкание объекту TransactionStatus
Spring. В TransactionStatus
я не смог ничего найти, чтобы закрыть / завершить транзакцию.
Редактировать: Я запускаю это с консоли Grails (grails console
)
Редактировать: Вот исключение нехватки памяти:
Exception thrown: Java heap space
java.lang.OutOfMemoryError: Java heap space
at org.hibernate.util.IdentityMap.entryArray(IdentityMap.java:194)
at org.hibernate.util.IdentityMap.concurrentEntries(IdentityMap.java:59)
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:113)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:65)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:655)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:732)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:701)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)