在大型事务中安全地清除休眠会话
我正在使用Spring + Hibernate进行操作,该操作需要创建和更新数十万个项目。像这样:
{
...
Foo foo = fooDAO.get(...);
for (int i=0; i<500000; i++) {
Bar bar = barDAO.load(i);
if (bar.needsModification() && foo.foo()) {
bar.setWhatever("new whatever");
barDAO.update(bar);
// commit here
Baz baz = new Baz();
bazDAO.create(baz);
// if (i % 100 == 0), clear
}
}
}
为了保护自己免受中间更改的丢失,我立即在以下位置提交更改:barDAO.update(bar)
HibernateTransactionManager transactionManager = ...; // injected by Spring
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus transactionStatus = transactionManager.getTransaction(def);
transactionManager.commit(transactionStatus);
在这一点上,我不得不说整个进程都在包装(是的,这是一个webapp)的事务中运行。org.springframework.orm.hibernate3.support.ExtendedOpenSessionInViewFilter
这一切都很好,但有一个例外:经过几千次更新/提交后,整个过程变得非常慢,很可能是由于Spring/Hibernate保存的对象数量不断增加,内存膨胀。
在仅休眠环境中,通过调用 可以很容易地解决。org.hibernate.Session#clear()
现在,问题:
- 什么时候是好时机?它是否具有较大的性能成本?
clear()
- 为什么对象不是自动的或已发布的/GCd?在提交后将它们保留在会话中有什么意义(在下一个迭代循环中,无论如何都无法访问它们)?我还没有做记忆转储来证明这一点,但我的良好感觉是,它们仍然存在,直到完全退出。如果这个问题的答案是“休眠缓存”,那么为什么在可用内存不足时缓存没有被刷新?
bar
baz
- 直接调用是否安全/建议(考虑到整个Spring上下文,如延迟加载等)?是否有任何可用的弹簧包装/对应物来实现相同的目标?
org.hibernate.Session#clear()
- 如果上述问题的答案为真,那么假设在循环内部调用对象会发生什么?如果是延迟加载方法怎么办?
foo
clear()
foo.foo()
感谢您的回答。