25

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

如果一个线程先完成并调用 clear(),那会影响其他线程吗?像for循环会有异常吗?

关闭()怎么样?

如果答案是“取决于”,我应该查看什么(类定义?方法调用?)以及在哪里(java 代码?注释?xml?)以了解它是如何依赖的?

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

谢谢你。

4

5 回答 5

32

这是完整的工作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();
    }
}
于 2013-09-09T12:43:27.923 回答
14

实体管理器不是线程安全的(源Java EE 6 教程)并且不能在线程之间共享。每个线程都需要使用自己的实体管理器,否则会发生不好的事情,不管是调用clear()还是close()调用。

但是,如果注入器使用自己的实体管理器注入每个线程,那么事情应该没问题。

Spring 和可能的其他 DI 框架将为真正的实体管理器注入一个基于 ThreadLocal 的代理到您的 bean 中。每个线程进行的调用将代理到实体管理器的真实线程本地实例——即使看起来实体管理器在多个线程之间共享,这也是事情的工作方式。

有关如何注入实体管理器的更多详细信息将有所帮助(Spring 等)

于 2013-02-15T04:22:51.207 回答
4

EntityManager 的管理有两种类型:容器管理和应用程序管理。对于应用程序托管,获取 EntityManager 的首选方法是通过 EntityManagerFactory。Java EE 教程是这样说的:

容器管理的实体管理器

使用容器管理的实体管理器,EntityManager 实例的持久性上下文由容器自动传播到在单个 Java Transaction API (JTA) 事务中使用 EntityManager 实例的所有应用程序组件。

JTA 事务通常涉及跨应用程序组件的调用。要完成 JTA 事务,这些组件通常需要访问单个持久性上下文。当通过 javax.persistence.PersistenceContext 注解将 EntityManager 注入应用程序组件时,就会发生这种情况。持久性上下文会随着当前 JTA 事务自动传播,映射到同一持久性单元的 EntityManager 引用提供对该事务内持久性上下文的访问。通过自动传播持久化上下文,应用程序组件不需要将 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

于 2013-02-15T04:20:30.947 回答
1

You normally have transactions around what you do with database objects. What each given thread sees about the changes made by other threads is controlled by 'transaction isolation' settings.

Start learning about different isolation settings and apply the right setting according to your needs. There is a trade-off between accuracy and speed. http://en.wikipedia.org/wiki/Isolation_%28database_systems%29

于 2013-02-15T05:26:44.573 回答
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 并发问题。

于 2016-08-26T08:34:15.823 回答