我阅读了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);
}
}
答案 0 :(得分:7)
在以下博客链接中对此行为进行了详细分析。 http://doanduyhai.wordpress.com/2011/11/21/spring-persistencecontext-explained/以下是我的摘要。
EntityManager
是一个java接口,它允许spring提供它自己的接口实现。 spring注入的实现使用动态代理来处理对实体管理器的调用。动态代理的行为方式如下。
如果@Transactional
中没有loadProductsByCategory
注释弹簧将在调用EntityManager
时创建em.createQuery
em的实例,spring将不会返回创建的Query对象通过JPA,但它会返回EntityManager
的Spring代理,这个春天代理将所有调用转发到Query
的实际执行,并等到getResult
或getSingleResult
或{{1调用它会立即关闭实体管理器。
因此,当没有executeUpdate
时,Spring将确保实体管理器尽快关闭,即在实体管理器上的每个方法调用之后或在提取结果集之后。在上面的示例中,如果您注释掉query.getResultList(),您将最终泄漏一个未关闭的实体管理器实例
@Transactional
当存在@Transactional属性时,spring事务管理器将在调用事务方法之前创建事务上下文。当事务方法调用实体管理器上的任何方法时,Spring将创建一个全新的EntityManager实例,并将其与当前的跨国实例相关联,如果事务方法调用另一个方法,该方法调用另一个方法,所有这些方法使用实体管理器,则实体管理器为在所有这些电话中共享。这是一个例子。
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添加到方法loadProductsByCategory才能将EntityManager绑定到线程?因为ProductDaoImpl类是单例并且在多线程中工作,但是entityManager不是线程安全的。
@Transactional导致spring将spring tx绑定到当前线程,然后实体管理器绑定到spring tx,spring tx通过本地线程的本地线程绑定。
Pro JPA 2书在第6章中对这些内容有一个不错的解释,它有点密集,它在Java EE的上下文中进行了解释,但春天的步骤是相同的。