EntityManager.getReference()致使的懶加載問題(Lazy)

爲了便與搜索直接把錯誤放出來: org.hibernate.LazyInitializationException: could not initialize proxy - no Session   。html

轉自:http://blog.sina.com.cn/s/blog_605f5b4f0100hfzz.htmljava

因爲EntityManager.getReference()致使的懶加載問題。數據庫

先說相同點

    這兩個方法都接受實體的 class和表明實體主鍵的對象做爲參數。因爲它們使用了Java泛型方法,無需任何顯示的類型轉換便可得到特定類型的實體對象。其中,在primaryKey上面廣泛使用了java5的autoboxing(自動裝箱)的特性。

    再者,就是二者都會在EntityManager關閉的狀況下拋出IllegalStateException - if this EntityManager has been closed. 在傳入的第一個參數不是實體或者第二個參數不是一個有效的主鍵的狀況下拋出

IlegalArgumentException - if the first argument does not denote an entity type or the second argument is not a valid type for that entity's primary key

 

 

不一樣點:

    find()返回指定OID的實體,若是這個實體存在於當前的persistence context中,那麼返回值是被緩存的對象;不然會建立一個新的實體,並從數據庫中加載相關的持久狀態。若是數據庫不存在指定的OID的記錄,那麼find()方法返回null。

    getReference()方法和find()類似。不一樣的是:若是緩存中沒有指定的實體,EntityManager會建立一個新的實體,可是不會當即訪問數據庫來加載持久狀態,而是在第一次訪問某個屬性的時候才加載。此外,getReference()方法不返回null,若是數據庫找不到相應的實體,這個方法會拋出javax.persistence.EntityNotFoundException。

EntityNotFoundException - if the entity state cannot be accessed
某些場合下使用getReference()方法能夠避免從數據庫加載持久狀態的性能開銷。

 

   *這裏要着重提出的是兩句話(重點):

   若是緩存中沒有指定的實體,EntityManager會建立一個新的實體,可是不會當即訪問數據庫來加載持久狀態,而是在第一次訪問某個屬性的時候才加載。

   好比,em.find()返回的實體,咱們就能夠對它進行各類操做,而若對em.getReference()返回的實體,因爲不會當即訪問數據庫來加載持久狀態,對它進行的操做極可能就會出現Exception,好比在對它返回的實體作getter操做時,因爲EntityManager對此採用延時加載,就會拋出org.hibernate.lazyinitializationexception could not initialize proxy no session

   所以將一個新的實體傳遞給事務的時候一般使用find()方法,而當不鏈接數據庫,不使用getter方法,即便用setter方法改變狀態時才使用getReference()方法。(這是因爲getReference返回是一個Proxy實體,即沒有加載持久狀態)

 

   某些場合下使用getReference()方法能夠避免從數據庫加載持久狀態的性能開銷。

    這也徹底是因爲getReference返回是一個Proxy實體.

    好比一個簡單的update操做,先使用find()獲取實體,然後使用實體的setter方法;或者是getReference()方法,然後使用實體的setter方法。

    對於前者JPA調用的SQL:select ****,然後纔是update ****

    對於後者:僅爲update *****

 

又如:

操做                                                                            執行的SQL

em.remove(em.getReference(Person.class,1))         delete from Person where personid = 1


em.remove(em.find(Person.class,1))                 select * from Person where personid =1

                                                   delete from Person where personid =1

 

   由此能夠看出,find()作了一次select的操做,而getReference並無作有關數據庫的操做,而是返回一個代理,這樣它就減小了鏈接數據庫和從數據庫加載持久狀態的開銷。
相關文章
相關標籤/搜索