代码之家  ›  专栏  ›  技术社区  ›  mindas

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

  •  31
  • mindas  · 技术社区  · 14 年前

    {
       ...
       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

    这一切都可以正常工作,但有一个例外:在几千次更新/提交之后,整个过程变得非常缓慢,很可能是由于Spring/Hibernate保存的对象数量不断增加导致内存膨胀。

    在只支持Hibernate的环境中,通过调用 org.hibernate.Session#clear() .

    现在,问题是:

    • 什么时候是吃饭的好时机 clear() ? 它的性能成本大吗?
    • 为什么物体不像 bar baz 是否自动发布/GCd?在提交之后将它们保留在会话中有什么意义(在下一个迭代循环中它们无论如何都是不可访问的)?我还没有做内存转储来证明这一点,但我的好感觉是,他们仍然存在,直到完全退出。如果答案是“Hibernate cache”,那么为什么可用内存上的缓存没有变低呢?
    • org.hibernate.Session#清除()
    • 如果上述问题的答案是真的,那么object会发生什么呢 foo 清除() foo.foo() 是延迟加载方法吗?

    谢谢你的回答。

    2 回复  |  直到 14 年前
        1
  •  48
  •   Pascal Thivent    14 年前

    什么时候是清除()的好时机?它的性能成本大吗?

    在刷新更改之后,以固定的时间间隔(理想情况下与JDBC批处理大小相同)。文档在关于的一章中描述了常见的习惯用法 Batch processing :

    13.1. Batch inserts

    为了控制尺寸 一级缓存的。

    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() 如果您不想跟踪实体,则显式地执行会话,仅此而已,这就是它的工作方式(您可能希望提交事务而不“丢失”实体)。

    打电话安全吗org.hibernate.Session#清除()直接

    flush() 挂起的更改不会丢失它们(除非这是您想要的),我看不出有任何问题(您当前的代码将丢失一个createevery100循环,但可能只是一些伪代码)。

    如果上述问题的答案为真,那么假设在循环中调用clear(),那么对象foo会发生什么情况?如果…怎么办福。福()是延迟加载方法?

    打电话 clear() Session ,使它们成为分离的实体。如果随后的调用需要一个实体被“附加”,它将失败。

        2
  •  1
  •   PEHLAJ Katherine    7 年前

    Session.refresh(obj) 为了继续下去。

    否则会出现以下错误:

    org.hibernate.NonUniqueObjectException