2011-11-07 82 views
2

我們正在開發一個(JavaSE-)應用程序,它通過持久的tcp連接與許多客戶端進行通信。客戶端連接,執行一些/許多操作(將其更新爲SQL數據庫)並關閉與服務器的應用程序/斷開連接。我們使用Hibernate-JPA並使用ThreadLocal變量自行管理EntityManager生命週期。實際上,我們在每個客戶請求上創建一個新的EntityManager實例,目前爲止工作正常。最近我們進行了一些分析,發現hibernate在每個UPDATE語句之前對數據庫執行SELECT查詢。這是因爲我們的實體處於分離狀態,並且每個新的EntityManager都首先將實體附加到持久化上下文。當服務器處於負載下時(這是因爲我們有一個寫入重度的應用程序),我們試圖消除這種泄漏,這導致大量的SQL開銷。EntityManager生命週期和持久客戶端 - 服務器通信

  • 首先,我們想到了2nd-Level-Cache。但是,我們發現,無論何時添加或刪除新項目,hibernate都會使Query-和Collection-Caches無效。
  • 第二個想法是,只要客戶端在服務器上登錄,我們就評估是否保持一個EntityManager。但我不知道這是否是一個「最佳實踐」,因爲它有一些缺點:線程安全性,EntityManager實例的管理開銷等。

簡而言之:我們正在尋找一種方法來獲取在每次UPDATE之前擺脫這些SELECT語句。那裏有任何想法?

回答

1

重新掛接分離的實體時,擺脫select語句的一種可能方式是使用Hibernate特有的update()操作而不是merge()

update()無條件運行update SQL語句並使分離對象持久化。如果會話中存在具有相同標識符的持久對象,則會引發異常。因此,它的時候你肯定是不錯的選擇是:

  1. 分離對象包括(應保存在數據庫中
  2. 保存該狀態是該請求打開會話的主要目標,即有修改狀態爲

在JPA 2.0,您可以訪問特定於Hibernate的操作如下,在該屆會議上加載實體使用相同的ID沒有其他操作):

em.unwrap(Session.class).update(o); 

參見:

+0

聽起來非常有益的事情。我會試試這個。 – infinikli

0

一個可能的選擇是使用StatelessSession作爲更新語句。我已經成功地在我的'重寫'應用程序中使用它。