簡體   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