2014-03-31 69 views
6

我正在開始一個新項目,並且我完全不熟悉JPA/Hibernate的使用。我試圖瞭解如何正確使用EntityManager。更確切地說,什麼時候實例化它們,我需要多少,我應該關閉它們,我是否應該把所有事情都交易在一起?努力理解EntityManager的正確使用

無論如何,在我當前的代碼中,當我嘗試讀取一個先前保存的實體時,出現了org.hibernate.LazyInitializationException。我會理解相反的情況(在事務中讀取一個antity,然後嘗試將讀取的實體保存在另一個事務中,但由於事務結束,實體未被管理,因此保存失敗),但我無法理解。

我把我的代碼放在GitHub上(https://github.com/GaetanLeu/intl),它只是幾個類。我主要在src /沙/ MessageSandbox.java,並在與以下堆棧跟蹤線28失靈:

Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session 
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164) 
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285) 
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185) 
    at entity.MessageKey_$$_jvstfcc_0.toString(MessageKey_$$_jvstfcc_0.java) 
    at java.lang.String.valueOf(String.java:2854) 
    at java.lang.StringBuilder.append(StringBuilder.java:128) 
    at com.google.common.base.Present.toString(Present.java:88) 
    at java.lang.String.valueOf(String.java:2854) 
    at java.io.PrintStream.println(PrintStream.java:821) 
    at sandbox.MessageSandbox.main(MessageSandbox.java:28) 

而且我從休眠說我的EntityManager已經存在一個警告,然後會發生什麼? EntityManagerFactory.createEntityManager方法是否返回現有的?

WARN: HHH000436: Entity manager factory name (intl) is already registered. If entity manager will be clustered or passivated, specify a unique value for property 'hibernate.ejb.entitymanager_factory_name' 

真的,我損失了大約何時創建EntityManagers ^^任何幫助,將不勝感激,但請簡單的解釋我真的很新的這一點。

哦,順便說一句,我想確切地說,我沒有使用Spring,我沒有EJB,我想現在手動操作EntityManagers直到我明白它。謝謝:)

回答

11

一個EntityManager管理着一個persistence context,其他字的數據庫狀態的內存快照。

What is a persistence object?

使用EntityManager加載的每個對象將在受控狀態(見entity life cycle),直至關閉EM。當實體managed,它所做的所有變化都將被跟蹤,然後沖洗時堅持EM。如果你訪問某些懶惰獲取屬性,請求將被自動觸發,動態的加載數據,但如果實體處於分離狀態下(如EM已被關閉)訪問lazy屬性會導致你的錯誤。

您的EM的

範圍(/生命週期)取決於你的執行上下文的。對於例如web應用,通常會爲每個http請求創建一個EM。

對於一個獨立的應用程序,你必須介意數據庫可以被其他應用程序/線程或不會被更新。如果可以,你的持久性上下文可能與數據庫狀態不一致,你應該爲每個工作單元(事務)創建它以避免這種情況。否則,您可以爲所有應用程序生命週期創建一次實例,並定期刷新它。

對於CRUD應用中的生命週期通常如下:

  • 創建EM
  • 取一些實體(它們被如此管理,任何訪問lazy屬性將加載從DB中的數據)
  • 關閉EM(實體現在脫離,到lazy屬性的任何訪問將導致LazyInitializationException中)
  • 顯示的數據傳送給用戶

在用戶更新驗證:

  • 創建EM
  • 打開一個交易
  • 合併(附加)更新的實體(這就是你所謂保存)(如果你已經設定了一些optmistic鎖定, EM將檢查實體版本,對這裏的數據庫)
  • 最終執行一些業務驗證或其他更新
  • 提交事務並關閉EM(變化將被刷新)

請記住,EM是一個輕量級的對象,便宜的創建和銷燬,而不是THREADSAFE。

順便說一下,JPA是一個Java EE規範,它是EJB的一部分(持久性部分)。其目標是用於Java EE容器環境(自JEE 6以來的Java EE應用服務器或CDI)。您仍然可以通過JPA合約在獨立模式下使用hibernate,但即使在這種情況下,也必須考慮與spring耦合以利用容器管理的功能。

+0

感謝您的回答。所以,如果明白你在說什麼,因爲我的「保存」功能和我的「讀取」功能都使用他們自己的EntityManager,並且因爲在保存我的實體後我沒有手動刷新,所以當我的讀取功能到達時, EM instanciated,我的實體沒有被堅持,無法找到。但是爲什麼我會得到'LazyInitializationException'而不是NPE,因爲它應該是整個實體沒有找到的,不是? – DeleteMePlease

+0

順便說一句,調用.persist時,爲什麼不立即堅持下去?有沒有實際上在數據庫中保留的「已提交」更改並不危險?特別是多個應用程序/ EM查詢這個數據庫?這裏最好的做法是什麼?每次堅持時都需要衝洗嗎? /提交? – DeleteMePlease

+0

「當我的閱讀功能達到第二個EM即刻,我的實體沒有被保存,也找不到。」不,你沒有誤解。在評估延遲獲取的屬性之前,您會收到導致您關閉EM的錯誤。 – Gab