2012-05-14 32 views
2

我讀了春天doc和它說:如何使用事務範圍的持久性上下文進行非事務性閱讀查詢?

的@PersistenceContext註釋有一個可選的屬性類型,默認爲 PersistenceContextType.TRANSACTION。默認情況下,您需要接收共享的 EntityManager代理。

  1. 這是否意味着我必須做的EntityManager工作事務?
  2. 它是如何工作的非事務性方法(閱讀查詢),如下面的代碼中的loadProductsByCategory?
  3. 「共享」是什麼意思?它如何使用EntityManager與他人共享?
  4. 我需要@Transactional以EntityManager的到線程綁定添加到方法loadProductsByCategory?因爲類ProductDaoImpl是單例並且在多線程中工作,但是entityManager不是線程安全的。

    @Service 
    public class ProductDaoImpl implements ProductDao { 
        @PersistenceContext 
        private EntityManager em; 
        public Collection loadProductsByCategory(String category) { 
         Query query = em.createQuery("from Product as p where p.category = :category"); 
         query.setParameter("category", category); 
         return query.getResultList(); 
        } 
        @Transactional 
        public void loadProductsByCategory(Product product) { 
         em.persist(product); 
        } 
    } 
    

回答

6

還有就是在下面的博客鏈接這種行爲進行詳細的分析。 http://doanduyhai.wordpress.com/2011/11/21/spring-persistencecontext-explained/這是我的總結。

EntityManager是一個java接口,使彈簧提供它自己的接口的實現。 Spring注入的實現使用動態代理來處理對實體管理器的調用。動態代理的行爲如下。

如果沒有@Transactional標註爲loadProductsByCategory春季將創建EntityManager的實例他們,當em.createQuery叫,春天不會返回由JPA創建的查詢對象,但它將返回的EntityManager今年春天代理春代理轉發所有調用真正落實Query和等待,直到getResultgetSingleResultexecuteUpdate被調用,它立即關閉實體管理器。

因此,當沒有@Transactional Spring將確保實體管理器儘快關閉,即在實體管理器上的每個方法調用之後或提取結果集之後。在你上面的例子,如果你註釋掉使用Query.getResultList()你最終將泄漏的實體管理器實例不會被關閉

public Collection loadProductsByCategory(String category) { 
     Query query = em.createQuery("from Product as p where p.category = :category"); 
     query.setParameter("category", category); 
     return null; 
     // a leak of an entity manager will happen because getResultList() was never called, so 
     // spring had no chance to close the entity manager it created when em.creaueQuery was 
     // invoked. 
     // return query.getResultList(); 
} 

當有@Transactional屬性Spring的事務管理器將創建一個事務上下文在調用事務方法之前。當事務方法調用實體管理器上的任何方法時,Spring將創建一個全新的EntityManager實例,並將其與當前的跨國實體相關聯(如果事務方法調用另一方法調用另一方法並且所有這些方法都使用實體管理器,那麼實體管理器是在所有這些呼叫中共享。這裏是一個例子。

main(..) 
{ 
    Foo foo = call spring to get foo instance 
    foo.doFoo(); 
} 

public class Foo { 
    @PersistenceContext 
    EntityManager em; 

    @Autowired 
    Bar bar; 

    @Transactional 
    public doFoo(){ 
     // before this method is called spring starts a spring transaction 
     em.createQuery(....) // here spring will create an instance of the Entity manager 
      // and assoicated with the current tx 
     bar.doBar(); // call bar transactional method 
    } 
} 

public calss Bar { 

     @PersistenceContext 
    EntityManager em; 


    @Transactional 
    public doBar(){ 
     // no tx is started here because one was already started in doFoo 
     em.createQuery(....) // spring looks under the current tx and finds that it has 
      // an entity manager, was created in the doFoo() method so this entity manager 
      // is used, This is what is meant by sharing of the entity manager. 
    } 
} 

回答你最後一個問題。

我是否需要將@Transactional添加到方法loadProductsByCategory以將EntityManager綁定到線程?因爲類ProductDaoImpl是單例並且在多線程中工作,但是entityManager不是線程安全的。

@Transactional會導致spring將spring tx綁定到當前線程,然後將實體管理器綁定到通過本地線程綁定到當前線程的spring tx。

Pro JPA 2書在第6章中對這個東西有一個很好的解釋,它有點密集,並且在Java EE的上下文中進行了解釋,但是對於spring來說步驟是一樣的。

相關問題