【问题标题】:JAVA: an EntityManager object in a multithread environmentJAVA:多线程环境中的 EntityManager 对象
【发布时间】:2013-01-31 00:50:12
【问题描述】:

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

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

close() 怎么样?

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

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

谢谢。

【问题讨论】:

  • 您能否详细介绍一下您的注入器机制以及 EntityManager 实例如何。例如它是一个 Spring 应用程序。您使用的是 OpenEntityManagerInViewFilter 吗?
  • 是的,当然。相同的 EntityManager 实例/对象正在库中传递,但我没有看到任何公共函数供我获取。所以我使用 com.google.inject.Injector 来获取它的实例,以便在我的函数中使用它。

标签: java persistence entitymanager


【解决方案1】:

这里是完整的工作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();
    }
}

【讨论】:

  • 一个关于如何在多线程应用程序中使用这个助手的简单例子会很棒。 :)
  • 简单而干净 - 不错 - 为我的线程应用程序测试过 - 工作正常 - 谢谢 :)
【解决方案2】:

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

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

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

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

【讨论】:

  • 谢谢!我很乐意为您提供帮助。我在图书馆找到了 guice,如果那是相关的。否则,请告诉我如何找到您想知道的内容。
  • "每个线程都需要使用自己的实体管理器,否则会发生不好的事情。"可能出了什么问题,请您详细说明。
【解决方案3】:

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

容器管理的实体管理器

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

JTA 事务通常涉及跨应用程序组件的调用。 要完成一个 JTA 事务,这些组件通常需要访问 单个持久性上下文。这发生在 EntityManager 是 通过注入到应用程序组件中 javax.persistence.PersistenceContext 注释。坚持 上下文随当前 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

【讨论】:

  • 谢谢。所以我知道有两种类型。那我怎么知道库使用的是哪种类型呢?
【解决方案4】:

您通常会围绕您对数据库对象所做的事情进行事务处理。每个给定线程看到的其他线程所做的更改由“事务隔离”设置控制。

开始了解不同的隔离设置,并根据您的需要应用正确的设置。准确性和速度之间存在权衡。 http://en.wikipedia.org/wiki/Isolation_%28database_systems%29

【讨论】:

    【解决方案5】:

    我离开了三年左右 :),但就在 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 并发问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-08
      • 2019-01-28
      • 1970-01-01
      • 1970-01-01
      • 2018-05-10
      • 2012-04-07
      • 1970-01-01
      相关资源
      最近更新 更多