min*_*das 31 java orm spring hibernate
我使用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
}
}
}
Run Code Online (Sandbox Code Playgroud)
为了保护自己不要丢失中间的变化,我会在以下情况后立即提交更改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);
Run Code Online (Sandbox Code Playgroud)
此时我不得不说整个进程在包含的事务中运行org.springframework.orm.hibernate3.support.ExtendedOpenSessionInViewFilter
(是的,这是一个webapp).
这一切都运行良好,但有一个例外:在几千次更新/提交之后,整个过程变得非常慢,很可能是由于内存因Spring/Hibernate保留的不断增加的对象而膨胀.
在仅限Hibernate的环境中,通过调用可以轻松解决这个问题org.hibernate.Session#clear()
.
现在,问题:
clear()
?它的性能成本是否很高?bar
或已baz
释放/ GCd?在提交之后将它们保留在会话中有什么意义(在下一个迭代循环中它们无论如何都无法访问)?我没有做过记忆转储来证明这一点,但我的好感觉是它们一直存在直到完全退出.如果答案是"Hibernate cache",那么为什么缓存在可用内存不足时刷新?org.hibernate.Session#clear()
直接调用(考虑整个Spring上下文,延迟加载等事情)?是否有任何可用的Spring包装器/对应物来实现相同的目的?foo
,假设clear()
在循环内部被调用?如果foo.foo()
是一个延迟加载方法怎么办?谢谢你的答案.
Pas*_*ent 47
何时是清除()的好时机?它的性能成本是否很高?
在刷新更改后,定期(理想情况下与JDBC批处理大小相同).该文档描述了有关批处理的章节中的常用习语:
13.1.批量插入
在使新对象持久化flush()然后清除()会话时,为了控制第一级缓存的大小.
Run Code Online (Sandbox Code Playgroud)Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); for ( int i=0; i<100000; i++ ) { Customer customer = new Customer(.....); session.save(customer); if ( i % 20 == 0 ) { //20, same as the JDBC batch size //flush a batch of inserts and release memory: session.flush(); session.clear(); } } tx.commit(); session.close();
这不应该有性能成本,反对:
为什么bar或baz等对象不会自动释放/ GCd?在提交之后将它们保留在会话中有什么意义(在下一个迭代循环中它们无论如何都无法访问)?
clear()
如果您不想保持跟踪实体,那么您需要明确地进行会话,这就是它的工作原理(人们可能希望在不"丢失"实体的情况下提交事务).
但是从我所看到的情况来看,bar和baz实例应该在明确之后成为GC的候选者.分析内存转储以查看正在发生的事情将会很有趣.
安全/建议直接调用org.hibernate.Session #clear()
只要你flush()
没有松开它们的挂起更改(除非这是你想要的),我没有看到任何问题(你的当前代码将松散每100个循环创建但可能它只是一些伪代码).
如果对上述问题的回答是正确的,那么对象foo会发生什么,假设在循环内调用clear()?如果foo.foo()是一个延迟加载方法怎么办?
调用clear()
将驱逐所有已加载的实例Session
,使它们成为分离的实体.如果后续调用要求实体"附加",则它将失败.
归档时间: |
|
查看次数: |
38932 次 |
最近记录: |