JAVA:多线程环境中的EntityManager对象

时间:2013-02-15 04:00:00

标签: java persistence entitymanager

如果我有多个线程,每个使用注入器来获取EntityManager对象,每个使用em对象来选择其他类对象的列表。准备用于for循环。

如果线程先完成并调用clear(),那会影响其他线程吗?就像for循环会有例外吗?

close()怎么样?

如果答案是“它取决于”,那么(类定义?方法调用?)和where(java code?annotation?xml?)应该看看它是如何依赖的?

我没有写源,我只是在没有文档的情况下使用别人的库。

谢谢。

5 个答案:

答案 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实例是线程安全的。

http://docs.oracle.com/javaee/6/tutorial/doc/bnbqw.html

答案 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并发问题。