Jac*_*cky 3 spring scope jpa transactional
我读了Spring文档,它说:
@PersistenceContext注释具有可选的属性类型,默认为PersistenceContextType.TRANSACTION.此默认值是接收共享EntityManager代理所需的内容.
我是否需要将@Transactional添加到方法loadProductsByCategory以便将EntityManager绑定到线程?因为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);
}
}
Run Code Online (Sandbox Code Playgroud)在以下博客链接中对此行为进行了详细分析.http://doanduyhai.wordpress.com/2011/11/21/spring-persistencecontext-explained/这是我对它的总结.
EntityManager是一个java接口,它允许spring提供它自己的接口实现.spring注入的实现使用动态代理来处理对实体管理器的调用.动态代理的行为方式如下.
如果没有@Transactional注释,因为在loadProductsByCategoryspring中会EntityManager在em.createQuery调用时创建em 的实例,spring将不会返回由JPA创建的Query对象,但是它将返回此Spring代理的Spring Proxy,EntityManager将所有调用转发给实际的实现Query并等待直到getResult或者getSingleResult或者executeUpdate被调用,它立即关闭实体管理器.
因此,当没有@TransactionalSpring时,将确保实体管理器尽快关闭,即在实体管理器上的每个方法调用之后或者在提取结果集之后.在上面的示例中,如果您注释掉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();
}
Run Code Online (Sandbox Code Playgroud)
当存在@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.
}
}
Run Code Online (Sandbox Code Playgroud)
回答你的上一个问题.
我是否需要将@Transactional添加到方法loadProductsByCategory以便将EntityManager绑定到线程?因为ProductDaoImpl类是单例并且在多线程中工作,但是entityManager不是线程安全的.
@Transactional导致spring将spring tx绑定到当前线程,然后实体管理器绑定到spring tx,spring tx通过本地线程的本地线程绑定.
Pro JPA 2书在第6章中对这些内容有一个不错的解释,它有点密集,它在Java EE的上下文中进行了解释,但春天的步骤是相同的.
| 归档时间: |
|
| 查看次数: |
3233 次 |
| 最近记录: |