Ste*_*Kuo 12 java grails spring hibernate transactions
我正在使用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()
}
Run Code Online (Sandbox Code Playgroud)
事实证明这很痛苦.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()
Run Code Online (Sandbox Code Playgroud)
这项工作必须更快,至少在最初阶段.每笔交易可保存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)
Run Code Online (Sandbox Code Playgroud)
Gar*_*vis 12
这是所有hibernate应用程序的常见问题,它是由hibernate会话的增长引起的.我猜测grails控制台以类似于'open view in view'模式的方式为你打开一个hibernate会话,我知道它用于正常的Web请求.
解决方案是获取当前会话并在每批后清除它.我不确定如何使用控制台获取spring bean,通常用于控制器或服务,您只需将它们声明为成员.然后你可以得到当前的会话sessionFactory.getCurrentSession().为了清除它只是调用session.clear(),或者如果你选择使用session.evict(Object)每个Person对象.
对于控制器/服务:
class FooController {
def sessionFactory
def doStuff = {
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()
}
// clear session here.
sessionFactory.getCurrentSession().clear();
}
}
// Save any remaining
for (Person p: batch)
p.save()
}
}
}
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助.
| 归档时间: |
|
| 查看次数: |
15370 次 |
| 最近记录: |