我的应用程序数据访问层是使用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的新手,我知道这不是最好的解决方案。我非常感谢以更好/更优雅的方式实施此要求的任何帮助!
谢谢!
答案 0 :(得分: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);
}
}
}
我现在使用MyEntityManagerFactoryImpl的实例(单例)注入我的DAO。然后,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"/>
....
干杯! (欢迎评论)
答案 1 :(得分:0)
我不确定这是否是一种干净的方法。我们可以使用spring应用程序上下文来获取spring application.xml中声明的entitymanagerfactory,而不是多次声明enitiymanagerfactory。
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();
答案 2 :(得分:0)
这也是我将来需要做的事情,因为我已将Spring DynamicDatasourceRouting加入书签
http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/
据我所知,这是使用一个PU,它被分配不同的数据源。也许这很有用。