【问题标题】:Ability to switch Persistence Unit dynamically within the application (JPA)能够在应用程序中动态切换持久性单元 (JPA)
【发布时间】:2011-02-15 11:25:26
【问题描述】:

我的应用程序数据访问层是使用 Spring 和 EclipseLink 构建的,我目前正在尝试实现以下功能 - 能够为用户动态切换当前/活动的持久性单元。我尝试了各种选择,最后做了以下事情。

在persistence.xml中,声明多个PU。创建一个具有与定义的 PU 一样多的 EntityManagerFactory 属性的类。这将充当工厂并根据我的逻辑返回适当的 EntityManager

public class MyEntityManagerFactory {
  @PersistenceUnit(unitName="PU_1")
  private EntityManagerFactory emf1;

  @PersistenceUnit(unitName="PU_2")
  private EntityManagerFactory emf2;

  public EntityManager getEntityManager(int releaseId) {
    // Logic goes here to return the appropriate entityManeger
 }
}

我的 spring-beans xml 看起来像这样..

<!--  First persistence unit  -->    
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="emFactory1">
  <property name="persistenceUnitName" value="PU_1" />
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager1">
  <property name="entityManagerFactory" ref="emFactory1"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager1"/>

第二个 PU 重复上述部分(名称如 emFactory2、transactionManager2 等)。

我是 JPA 新手,我知道这不是最佳解决方案。感谢您以更好/优雅的方式实施此要求的任何帮助!

谢谢!

【问题讨论】:

    标签: spring jpa eclipselink


    【解决方案1】:

    首先感谢 user332768 和 bert。我尝试使用bert提供的链接中提到的AbstractRoutingDataSource,但在尝试连接我的jpa层(eclipselink)时迷路了。我通过一些修改恢复了我的旧方法。该解决方案看起来更干净(恕我直言)并且工作正常。 (在运行时切换数据库并在同一个事务中写入多个数据库)

    public class MyEntityManagerFactoryImpl implements MyEntityManagerFactory, ApplicationContextAware {
    
        private HashMap<String, EntityManagerFactory> emFactoryMap;
    
        public EntityManager getEntityManager(String releaseId) {
            return SharedEntityManagerCreator.createSharedEntityManager(emFactoryMap.get(releaseName));
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext)
                throws BeansException {
            Map<String, LocalContainerEntityManagerFactoryBean> emMap = applicationContext.getBeansOfType(LocalContainerEntityManagerFactoryBean.class);
            Set<String> keys = emMap.keySet();
            EntityManagerFactory entityManagerFactory = null;
            String releaseId = null;
            emFactoryMap = new HashMap<String, EntityManagerFactory>();
            for (String key:keys) {
                releaseId = key.split("_")[1];
                entityManagerFactory = emMap.get(key).getObject();
                emFactoryMap.put(releaseId, entityManagerFactory);
            }
        }
    }
    

    我现在向我的 DAO 注入 MyEntityManagerFactoryImpl 的一个实例(单例)。然后,dao 将简单地使用所需的版本调用 createSharedEntityManager,并为该数据库获取正确的 EntityManager。 (请注意,我现在使用的是应用程序管理的 EntityManager,因此我必须在我的 dao 中明确关闭它们)

    我也搬到了 jta 事务管理器(管理跨多个数据库的事务) 这就是我的 spring xml 现在的样子。

    ...
    <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="em_Rel1">
            <property name="persistenceUnitName" value="PU1" />
    </bean>
    <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="em_Rel2">
            <property name="persistenceUnitName" value="PU2" />
    </bean>
    
    <bean class="org.springframework.transaction.jta.JtaTransactionManager" id="jtaTransactionManager">
    </bean>
    <tx:annotation-driven transaction-manager="jtaTransactionManager"/>
    ....
    

    干杯! (欢迎cmets)

    【讨论】:

      【解决方案2】:

      我不确定这是否是一种干净的方法。不用多次声明enitiymanagerfactory,我们可以使用spring application context来获取spring application.xml中声明的entitymanagerfactory。

      hm = applicationContext.getBeansOfType(org.springframework.orm.jpa.LocalEntityManagerFactoryBean.class);
      EntityManagerFactory emf = ((org.springframework.orm.jpa.LocalEntityManagerFactoryBean) hm.get("&emf1")).getNativeEntityManagerFactory();
      EntityManagerFactory emf2 = ((org.springframework.orm.jpa.LocalEntityManagerFactoryBean) hm.get("&emf2")).getNativeEntityManagerFactory();
      

      【讨论】:

        【解决方案3】:

        这也是我将来需要做的事情,为此我已经为 Spring DynamicDatasourceRouting 添加了书签

        http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/

        据我了解,这是使用一个 PU,它被分配了不同的数据源。也许有帮助。

        【讨论】:

          猜你喜欢
          • 2013-09-06
          • 2019-02-23
          • 1970-01-01
          • 2013-02-15
          • 2014-06-25
          • 2021-02-17
          • 2014-03-28
          • 2012-07-26
          • 1970-01-01
          相关资源
          最近更新 更多