繁体   English   中英

在大事务中安全地清除Hibernate会话

[英]Safely clearing Hibernate session in the middle of large transaction

我使用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);

此时我不得不说整个进程在包含在org.springframework.orm.hibernate3.support.ExtendedOpenSessionInViewFilter中的事务中运行(是的,这是一个webapp)。

这一切都运行良好,但有一个例外:在几千次更新/提交之后,整个过程变得非常慢,很可能是由于内存因Spring / Hibernate保留的不断增加的对象而膨胀。

在仅Hibernate环境中,通过调用org.hibernate.Session#clear()可以很容易地解决这个问题。

现在,问题:

  • 何时是clear()的好时机? 它的性能成本是否很高?
  • 为什么barbaz等对象不会自动释放/ GCd? 在提交之后将它们保留在会话中有什么意义(在下一个迭代循环中它们无论如何都无法访问)? 我没有做过记忆转储来证明这一点,但我的好感觉是它们一直存在直到完全退出。 如果答案是“Hibernate cache”,那么为什么缓存在可用内存不足时刷新?
  • 安全/建议直接调用org.hibernate.Session#clear() (考虑到整个Spring上下文,延迟加载等等)? 是否有任何可用的Spring包装器/对应物来实现相同的目的?
  • 如果对上述问题的回答是正确的,那么对象foo会发生什么,假设在循环内调用clear() 如果foo.foo()是一个延迟加载方法怎么办?

谢谢你的答案。

何时是清除()的好时机? 它的性能成本是否很高?

在刷新更改后,定期(理想情况下与JDBC批处理大小相同)。 该文档描述了有关批处理的章节中的常用习语:

13.1。 批量插入

在使新对象持久化flush()然后清除()会话时,为了控制第一级缓存的大小。

 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()clear()会话,这就是它的工作方式(人们可能希望在不“丢失”实体的情况下提交事务)。

但是从我所看到的情况来看,bar和baz实例应该在明确之后成为GC的候选者。 分析内存转储以查看正在发生的事情将会很有趣。

安全/建议直接调用org.hibernate.Session #clear()

只要你flush()挂起的更改就不会松开它们(除非这是你想要的),我没有看到任何问题(你的当前代码会松动每100个循环创建一个但是它可能只是一些伪代码)。

如果对上述问题的回答是正确的,那么对象foo会发生什么,假设在循环内调用clear()? 如果foo.foo()是一个延迟加载方法怎么办?

调用clear()Session驱逐所有已加载的实例,从而使它们成为分离的实体。 如果后续调用要求实体“附加”,则它将失败。

我只想指出,在清除会话后,如果要继续使用会话中的某些对象,则必须使用Session.refresh(obj)才能继续。

否则您将收到以下错误:

org.hibernate.NonUniqueObjectException

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM