我正在使用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文档, withTransaction
将闭包传递给Spring的TransactionStatus
对象。我在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)