如果我有多个线程,每个使用注入器来获取EntityManager对象,每个使用em对象来选择其他类对象的列表。准备用于for循环。
如果线程先完成并调用clear(),那会影响其他线程吗?就像for循环会有例外吗?
close()怎么样?
如果答案是“它取决于”,那么(类定义?方法调用?)和where(java code?annotation?xml?)应该看看它是如何依赖的?
我没有写源,我只是在没有文档的情况下使用别人的库。
谢谢。
答案 0 :(得分:30)
这是完整的工作thread-safe Entity Manager Helper
。
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class EntityManagerHelper {
private static final EntityManagerFactory emf;
private static final ThreadLocal<EntityManager> threadLocal;
static {
emf = Persistence.createEntityManagerFactory("Persistent_Name");
threadLocal = new ThreadLocal<EntityManager>();
}
public static EntityManager getEntityManager() {
EntityManager em = threadLocal.get();
if (em == null) {
em = emf.createEntityManager();
// set your flush mode here
threadLocal.set(em);
}
return em;
}
public static void closeEntityManager() {
EntityManager em = threadLocal.get();
if (em != null) {
em.close();
threadLocal.set(null);
}
}
public static void closeEntityManagerFactory() {
emf.close();
}
public static void beginTransaction() {
getEntityManager().getTransaction().begin();
}
public static void rollback() {
getEntityManager().getTransaction().rollback();
}
public static void commit() {
getEntityManager().getTransaction().commit();
}
}
答案 1 :(得分:12)
实体管理器不是线程安全的(源Java EE 6 tutorial),并且不能在线程之间共享。每个线程都需要使用自己的实体管理器,否则无论clear()
还是close()
调用都会发生不好的事情。
但是,如果注入器使用自己的实体管理器注入每个线程,那么事情应该没问题。
Spring和可能的其他DI框架会将真实实体管理器的基于ThreadLocal的代理注入到bean中。每个线程所做的调用将代理实体管理器的真实线程本地实例 - 这就是事情可以工作的方式,即使它可能看起来实体管理器在多个线程之间共享。
有关如何注入实体管理器的更多细节将有所帮助(Spring等)
答案 2 :(得分:4)
管理EntityManager有两种类型:容器管理和应用程序管理。对于托管的应用程序,获取EntityManager的首选方法是通过EntityManagerFactory。 Java EE教程说:
容器管理实体经理
使用容器管理的实体 manager,EntityManager实例的持久化上下文是 由容器自动传播到所有应用程序 在单个Java中使用EntityManager实例的组件 事务API(JTA)事务。
JTA事务通常涉及跨应用程序组件的调用。 要完成JTA事务,这些组件通常需要访问 单个持久化上下文。当EntityManager出现时会发生这种情况 通过以下方式注入应用程序组件 javax.persistence.PersistenceContext注释。坚持不懈 使用当前JTA事务自动传播上下文, 和映射到相同持久性的EntityManager引用 unit提供对其中持久性上下文的访问 交易。通过自动传播持久化上下文, 应用程序组件不需要传递对EntityManager的引用 彼此之间的实例,以便在单个内进行更改 交易。 Java EE容器管理生命周期 容器管理的实体经理。
要获取EntityManager实例,请将实体管理器注入 应用程序组件:
@PersistenceContext EntityManager em;
应用程序管理的实体经理
使用应用程序管理的实体管理器,另一方面 手,持久化上下文不会传播到应用程序 组件和EntityManager实例的生命周期由 申请。
应用程序需要时使用应用程序管理的实体管理器 访问未使用JTA传播的持久性上下文 特定持久性中跨EntityManager实例的事务 单元。在这种情况下,每个EntityManager创建一个新的,隔离的 持久化上下文。 EntityManager及其关联的持久性 应用程序显式创建和销毁上下文。他们 也可以在直接注入EntityManager实例时使用 完成,因为EntityManager实例不是线程安全的。 EntityManagerFactory实例是线程安全的。
答案 3 :(得分:1)
您通常会处理有关数据库对象的事务。每个给定线程看到的其他线程所做的更改由“事务隔离”设置控制。
开始了解不同的隔离设置,并根据您的需要应用正确的设置。在准确性和速度之间进行权衡。 http://en.wikipedia.org/wiki/Isolation_%28database_systems%29
答案 4 :(得分:0)
我离开了三年左右:),但就EJB中注入EntityManager而言,这里有一个指向Adam Bien博客条目的链接http://www.adam-bien.com/roller/abien/entry/is_in_an_ejb_injected
从那里复制粘贴:
“您可以将EntityManager直接注入到EJB中。但是:它是否是线程安全的?:
@Stateless
public class BookServiceBean implements BookService {
@PersistenceContext EntityManager em;
public void create(Book book) { this.em.persist(book);}
}
“
答案是,再次复制粘贴:
“无论是同时调用一个方法还是多个方法,使用没有任何进一步配置的EJB都是线程安全的。容器关心调用的序列化。”,
这可能更清楚,但它暗示您可以在无状态会话bean中注入EntityManager,而不必担心EntityManager并发问题。