2012-12-04 42 views
3

我有大约10个EntityManagers的Java EE应用程序(EM数量可能会增加)。我的应用程序还包含许多无状态,有状态和消息驱动的bean。在Java EE应用程序中处理多个EntityManager

而不是注入每个豆我的EM与@PersistenceContext(和2个方法来检测哪些EM用户),我可能将所有这些内容存储在一个单身bean和访问其他豆。像那样,不用担心可维护性。

尽管如此,是否将线程安全地存储在一个单例bean中?会出现瓶颈吗?

另一个解决方案是创建一个抽象类,所有的bean都会扩展它。

什么是更好的解决方案?

回答

2

容器管理实体管理器将自动与当前JTA事务一起传播,并且映射到相同持久性单元的引用可提供对该事务内的持久性上下文的访问。因此,除了并发性问题之外,共享一个来自单例的实体管理器并不是一个好习惯,它会导致为您在bean上调用的每个方法使用相同的事务上下文。
一个简单的解决方案就是将您的需求注入EntityManagerFactory引用并创建EntityManager调用createEntityManager()方法的对象。 缺点是你应该手动管理交易,不再依赖容器。
否则,另一种方法可能是将所有实体管理器注入到主要企业bean中,并使用传递适当管理器的方法在服务bean中实现业务逻辑。 的后者的解决方案的例子:

@Stateless 
class MainBean { 
    @PersistenceContext EntityManager em1; 
    @PersistenceContext EntityManager em2; 
    ... 
    @EJB WorkerBean1 workerBean1; 
    @EJB WorkerBean2 workerBean2; 
    ... 
    void method1(Object param1, Object param2) { 
     workerBean1.method1(em1, param1, param2); 
    } 

    void method2(Object param1, Object param2, Object param3) { 
     workerBean2.method2(em2, param1, param2, param3); 
    } 
    ... 
} 

@Stateless 
class WorkerBean1 { 
    void method1(EntityManager em, Object param1, Object param2) { 
     ... 
    } 
    ... 
} 

@Stateless 
class WorkerBean2 { 
    void method2(EntityManager em, Object param1, Object param2, Object param3) { 
     ... 
    } 
    ... 
} 
+0

谢谢。好的,所以我必须忘记singleton和注入'EntityManagerFactory',因为我想保持容器事务的基础。所以,如果我理解的很好,你建议我把每一个新的EM都复制到每个bean中?这就是我想要避免的可维护性问题。如果不是这种情况,谢谢你的解释。 –

+1

是的,如果您希望使用容器管理的交易,这是唯一的方法。这与在单体中声明实体管理器没什么两样。您可以应用适配器设计模式,与所有实体管理器一起开发一个独特的企业bean,而不是一个单独的企业bean(因此,当您添加或删除管理器时,您只需单点修改);这个bean实现了所有接口并将方法调用路由到其他企业bean,并将它们传递给适当的实体管理器。不幸的是,缺点是后者的企业bean方法需要将管理者作为参数。 – remigio

+0

确定,所以其他bean将扩展我所有存储EM的独特bean?我只想要有一个独特的地方,其中EM是硬编码的。英语不是我的语言,有时我有问题来理解技术术语,原谅我。 –

4

经理不应该是线程安全的,所以你不应该通过共享一个单身的人的实体。这与您为什么不应该将实体管理器注入到Servlet中的原因是相同的,以及为什么在这样的Web组件中从JNDI进行查找 - 应该随时返回实体管理器的不同实例。

在实践中,某些实现可能会提供一个线程安全的实体管理器,因此在测试期间它似乎可以工作。但是,为了便于携带并保护您免于升级困境,您绝不应该依赖这一点。

您可以将所有的实体管理器定义在一个bean中,而不是从需要实体管理器的地方注入,而不是从一个通用基类继承。

E.g.

@Stateless 
public class EntityManagerProviderBean { 

    @PersistenceContext(unitName="foo") 
    private EntityManager entityManagerFoo; 

    @PersistenceContext(unitName="bar") 
    private EntityManager entityManagerBar; 

    public EntityManager getEntityManager() { 
     return ...? entityManagerFoo : entityManagerBar; 
    } 
} 

(其中...是逻辑分析,你用它来选择合适的实体管理器)

注入到这个bean的需要实体管理器:

@Stateless 
public class MyService { 

    @EJB 
    private EntityManagerProviderBean entityManagerProvider; 

    public void doStuff(MyEntity myEntity) { 
     entityManagerProvider.getEntityManager().update(myEntity); 
    } 

} 

或者以下可能会更加整齐:

@Stateless 
@PersistenceContexts({ 
    @PersistenceContext(unitName="foo", name = "fooENC"), 
    @PersistenceContext(unitName="bar", name = "barENC") } 
) 
public class EntityManagerProviderBean { 

    @Resource 
    private EJBContext context; 

    public EntityManager getEntityManager() { 
     return (EntityManager) context.lookup(... ? "fooENC" : "barENC"); 
    } 
} 

T他最后一个例子将所有持久性上下文映射到bean的ENC中,在那里可以方便地以编程方式检索它们。

不幸的是,人们忘了后者的语法增加测试的TCK,随后各大厂商忘记了实现它(见http://java.net/jira/browse/JPA_SPEC-38https://issues.jboss.org/browse/AS7-5549),因此,如果这个工程的服务器上测试。

+0

你知道IBM WAS如何处理(EntityManager)context.lookup(“blah”)吗? EntityManager是否每次都返回一个新的(每个PU有1个EMF),还是每次都是相同的EM(每个PU有1个EM)?首先会很棒,其次会很糟糕。但我无法在任何地方找到答案。 – djb

0

复合持久单元 - 的Java EE

处理多个实体管理器的方式,即多个持久化单元,在Java EE是使用复合持久性单元(CPU)。这种复合持久性单元可以通过EE网络应用程序中的一个单一点来评估,一个数据层。尽管为了与@PersistenceContext一起工作,这需要是@Stateless EE bean。

已经引入了复合持久单元,以便在各种Java应用程序中重用实体类。 CPU是企业架构的一项功能。我选择使用EclipseLink作为展示,因为我从正在运行的生产应用程序中获得了积极的体验。

介绍

在某些情况下,实体包含在一台服务器所需的景观在更多的网络服务的一般数据。以一个通用的'名称地址'实体,'用户密码角色'实体,'文档关键词索引'实体等为例。复合持久性单元的实现方式便于每个实体定义的源在只有一个地方('单点定义')。这些实体定义可以随后包含在每个需要此实体访问的Java Web应用程序中。复合持久性单元的

工作

复合持久性单元的工作由下面的教程所示:EclipseLink composite persistence units

复合持久单元的概念的工作原理是第一限定部件持久单元。每个成员持久性单元可以与不同的数据库关联,但成员持久性单元也可以全部引用相同的实际数据库。我有后者的经验,EclipseLink(版本2.6.4)与一个Postgress数据库结合使用。

Maven需要使所需的模块化方法成为可能。

设置在persistence.xml中

一种复合持久单元构件的定义如下:方案一组相关实体(爪哇@Entity班),一个接一个,专用的Maven模块中的。在这个Maven模块中定义一个复合持久化单元成员(重要!)。复合单元成员PuPersonData涉及表征人员数据的这组相关实体。定义成员持久化单元PuPersonData为(

<persistence-unit name="PuPersonData" transaction-type="JTA"> 
... 
    <jta-data-source>jdbc/PostgresDs</jta-data-source> 
... 

)。

在第二Maven的模块,定义另一复合持久单元构件,PuWebTraffic(

<persistence-unit name="PuWebTraffic" transaction-type="JTA"> 
... 
    <jta-data-source>jdbc/PostgresDs</jta-data-source> 
... 

)。在此处包括其他存储关于Web事务,登录,会话等的数据的实体(用@Entity表示的Java类) 不用说明,两个组合持久性单元成员必须与实体不相交,实体中不允许重叠-names。

两个持久性单元成员在他们的XML-定义属性:

<properties> 
    <property name="eclipselink.composite-unit.member" value="true"/> 
    ... 
</properties> 

复合持久单元

我们现在在第三Maven的定义模块复合持久单元CPuPersonSessionData同时包含持久性单元成员PuPersonData和PuWebTraffic。

<persistence-unit name="CPuPersonSessionData" transaction-type="JTA"> 

该复合持久单元CPuPersonSessionData指两个持久性单元构件,PuPersonData和PuWebTraffic,通过包括从所述两个有关的Maven模块的编译的结果的罐子的手段。

... 
    <jar-file>PuPersonData.jar</jar-file> 
    <jar-file>PuWebTraffic.jar</jar-file> 
... 

在复合持久性单元的XML的定义,下面的属性需要设置

<properties> 
    <property name="eclipselink.composite-unit" value="true"/> 
    ... 
</properties> 

此设置确保该复合持久性单元由Java EE的区别对待大于它的持久性单元成员。

在Java中

在所要存储和检索与两个人的数据和业务数据实体的Java Web应用程序使用持久性单元中,只有复合持久单元包括

@Stateless 
public class DataLayer { 

    @PersistenceUnit(unitName="CPuPersonSessionData") 
    EntityManager em; 
    ... 

现在可以对包含在其中一个合成实体成员中的每个实体执行正常'em'操作,例如persist,findmerge

在Payara下,该组合持久性单元不需要XA事务来处理与每个持久性单元成员有关的实体。

的Maven

行家 POM文件需要包含规格为有关的模块。

... 
    <modules> 
      <module>PersonData</module> 
      <module>WebTraffic</module> 
      <module>PersonSessionData</module> 
    </modules> 
... 

每个模块的POM文件需要配置为正常的Maven项目,指的是父POM文件。

陷阱:

  • 您需要正确配置的Maven多模块项目,这可能有点棘手。每个复合持久性单元成员构成一个独立的Maven模块。此外,复合持久性单元是一个单独的Maven模块。成员需要先用Maven序列进行编译。
  • 编译复合持久单元的模块时,需要找到复合持久单元中的'jars'。
  • 每个合成持久性单元成员的实体需要在结果'jar'中直接存在于'classes'目录中(通过Maven添加到实体的额外路径是可能的但复杂的)。
  • 持久性单元成员的'jars'需要在'classes'目录中可供复合持久单元找到它们。

获得的好处是一个整洁的企业数据层,可与可重用实体一起工作,每个实体都有一个中心定义。此外,可以执行跨单元原生SQL查询。我也得到了这个工作。

文档指出,当复合持久性单元成员在不同的实际数据库上运行时,跨单元本机查询将不起作用。这应该仍然被验证。