【问题标题】:how to dynamically modifying unitName in @PersistenceContext如何在@PersistenceContext 中动态修改unitName
【发布时间】:2016-02-20 19:51:10
【问题描述】:

我正在使用 JPA 2.1,我有类似的东西

public class EntityManagerProducer {
    @Produces
    @PersistenceContext(unitName="first_PU")
    private EntityManager em;
    ...

如何动态修改@PersistenceContext(unitName = "somer_PU") 中的unitName 以使用其他实体管理器?这可能吗?

非常重要的更新

我有一个部署的应用程序,persistence.xml 看起来像这样:

<persistence-unit name="db1" transaction-type="JTA">
<jta-data-source>java:/jboss/datasources/PostgresDS</jta-data-source>
<properties>
  <property name="hibernate.hbm2ddl.auto" value="update"/>
  <property name="hibernate.show_sql" value="true"/>
  <property name="hibernate.format_sql" value="true"/>
  <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
  <property name="hibernate.cache.use_second_level_cache" value="false"/>
  <property name="hibernate.jdbc.batch_size" value="50"/>
  <property name="hibernate.jdbc.batch_versioned_data" value="true"/>
  <property name="hibernate.order_inserts" value="true"/>
  <property name="hibernate.order_updates" value="true"/>
  <property name="hibernate.generate_statistics" value="true"/>
  <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
  <property name="jboss.entity.manager.jndi.name" value="java:app/entitymanager/db1"/>
  <property name="jboss.entity.manager.factory.jndi.name" value="java:app/entitymanagerfactory/db1"/>
</properties>

在运行时,可以修改 persistence.xml 并添加另一个持久性单元,但我需要一种方法来获取我需要的实体管理器,方法是传递持久性单元的名称或其他内容,然后将其用于我想要的。然后我可以提供另一个持久性单元名称并获得不同的实体管理器。当然我希望交易过程仍然是容器管理。

【问题讨论】:

  • 对不起,但我仍然认为在运行时更改持久性单元名称没有任何意义。你可以解释吗?您的应用程序是否需要与多个不同的数据库通信? 在运行时,可以修改persistence.xml ...是什么意思?
  • 我的意思是,当应用程序部署在服务器上时,它可以添加更多的持久性单元。是的,我需要我的应用程序可以与多个不同的数据库通信。
  • 但是仅仅动态定义数据源还不够吗?老实说,您可以在您的 java 代码中连接到任何数据库:开玩笑地打开一个连接并执行所需的 SQL 语句(不使用EntityManager)。顺便说一句:您的应用程序与数据库的数量是固定的吗?

标签: jpa ejb persistence cdi entitymanager


【解决方案1】:

相信我,您不想修改现有PersistenceContext 中的unitName。我几乎可以肯定,您想要实现的只是让第二个 EntityManager 指向不同的数据库,对吧?

那么一个自然的方法是:

public class SomeClass {

    @PersistenceContext(unitName = "first_PU")
    EntityManager firstEntityManager;

    @PersistenceContext(unitName = "somer_PU")
    EntityManager secondEntityManager;

    // ...
}

个人建议

  1. 还请注意,在使用 EJB 时,您不必为 EntityManager 创建 Producer 方法,因为输入 @PersistenceContext(...) 就足够了。

  2. 强烈建议不要使用以下内容:

    @Produces
    @PersistenceContext(unitName="first_PU")
    private EntityManager em;
    

    因为默认范围是@Dependent。 @RequestScoped 或 @TransactionScoped 会更好。

  3. 您可以使用 CDI 和注释限定符来代替硬编码的单元名称:

    @Inject
    private @FirstDB EntityManager firstEntityManager;
    
    @Inject
    private @SecondDB EntityManager secondEntityManager;
    

    但是你需要:

    @Produces
    @RequestScoped // or other
    @FirstDB
    public EntityManager createEntityManagerA() {
        return firstEmf.createEntityManager();
    }
    
    @Produces
    @RequestScoped  // or other
    @SecondDB
    public EntityManager createEntityManagerB() {
        return secondEmf.createEntityManager();
    }
    

您可以找到很多关于 CDI 和生成多个 EntityManager 的有用信息here。

【讨论】:

  • 您好,G. Demecki,您的回答和您给我的链接对我很有帮助,它们帮助我澄清了一些疑问。但不幸的是,我的情况有点复杂,因为我不知道在运行时我会使用什么持久性单元,而且我不知道可以有多少,所以我可以硬编码那些 Entitymanagers。我稍微更新了我的问题,如果需要更多信息,请告诉我。
  • 这个方法创建的EntityManager需要关闭吗?
【解决方案2】:

这是不可能的。如果您需要动态持久性单元名称,则需要完全避免 EE 集成并直接使用 javax.persistence.Persistence 类,但我不建议这样做。作为替代方案,您可以为所有持久性单元注入 EntityManager/Factory,然后使用 switch 语句或类似语句选择正确的。

【讨论】:

  • 您可以推荐一个使用您提出的替代方案的示例吗?
猜你喜欢
  • 1970-01-01
  • 2011-08-15
  • 2019-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多