Возможность динамического переключения модуля постоянства в приложении (JPA) - PullRequest
4 голосов
/ 04 мая 2010

Уровень доступа к данным моего приложения построен с использованием Spring и EclipseLink, и в настоящее время я пытаюсь реализовать следующую функцию - Возможность динамического переключения текущего / активного модуля персистентности для пользователя. Я пробовал разные варианты и в итоге сделал следующее.

В файле persistence.xml объявите несколько PU. Создайте класс с таким количеством атрибутов EntityManagerFactory, как определено PU. Это будет действовать как фабрика и возвратит соответствующий 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
 }
}

Мой весенний бобовый 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, TransactionsManager2 и т. Д.).

Я новичок в JPA и знаю, что это не лучшее решение. Я ценю любую помощь в выполнении этого требования лучшим / элегантным способом!

Спасибо!

Ответы [ 3 ]

1 голос
/ 12 мая 2010

Прежде всего, благодаря user332768 и bert. Я попытался использовать AbstractRoutingDataSource, как упомянуто в ссылке, предоставленной bert, но заблудился, пытаясь подключить мой слой 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 с экземпляром (singleton) MyEntityManagerFactoryImpl. Затем дао просто вызовет createSharedEntityManager с необходимым выпуском и получит правильный EntityManager для этой базы данных. (Обратите внимание, что сейчас я использую EntityManager, управляемый приложением, и, следовательно, я должен явно закрыть их в моем dao)

Я также перешел в диспетчер транзакций jta (для управления транзакциями в нескольких базах данных) Вот так выглядит мой весенний 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"/>
....

Ура! (комментарии приветствуются)

0 голосов
/ 05 мая 2010

Это то, что мне нужно сделать и в будущем, для этого я добавил в закладки Spring DynamicDatasourceRouting

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

Насколько я понимаю, это использование одного PU, которому назначаются разные источники данных. Возможно, это полезно.

0 голосов
/ 05 мая 2010

Я не уверен, что это чистый метод. Вместо того, чтобы объявлять enitiymanagerfactory несколько раз, мы можем использовать контекст приложения Spring, чтобы получить объект entitymanagerfactory, объявленный в файле application.xml.

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();
...