還有就是在下面的博客鏈接這種行爲進行詳細的分析。 http://doanduyhai.wordpress.com/2011/11/21/spring-persistencecontext-explained/這是我的總結。
EntityManager
是一個java接口,使彈簧提供它自己的接口的實現。 Spring注入的實現使用動態代理來處理對實體管理器的調用。動態代理的行爲如下。
如果沒有@Transactional
標註爲loadProductsByCategory
春季將創建EntityManager
的實例他們,當em.createQuery
叫,春天不會返回由JPA創建的查詢對象,但它將返回的EntityManager
今年春天代理春代理轉發所有調用真正落實Query
和等待,直到getResult
或getSingleResult
或executeUpdate
被調用,它立即關閉實體管理器。
因此,當沒有@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來說步驟是一樣的。
來源
2013-05-15 05:01:08
ams