我使用的是spring 3.2.3和JPA 2.0。我想基于枚举动态连接我的数据库。我有这样的配置
<bean id="legacyDataSource" name="myLegacyDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" lazy-init="true">
<property name="driverClassName" value="${jdbc.legacy.driverClassName}" />
<property name="url" value="${jdbc.legacy.url}" />
<property name="username" value="${jdbc.legacy.username}" />
<property name="password" value="${jdbc.legacy.password}" />
</bean>
<bean id="modernDataSource" name="myModernDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" lazy-init="true">
<property name="driverClassName" value="${jdbc.modern.driverClassName}" />
<property name="url" value="${jdbc.modern.url}" />
<property name="username" value="${jdbc.modern.username}" />
<property name="password" value="${jdbc.modern.password}" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
</bean>
<bean id="placeholderProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database/jdbc.properties" />
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="order" value="1" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="emf" name="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" lazy-init="true">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="vendorAdaptor" />
<property name="packagesToScan" value="com.softech.ls360.integration.regulators.plcb.domain"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
我宣称枚举像
public enum DatabaseType {
LEGACY,
MODERN
} //end of enum DatabaseType
现在我想在我的主类中基于枚举数据库切换。为此,我想我需要改变
<property name="dataSource" ref="dataSource" />
运行时<bean id="emf" name="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" lazy-init="true">
中的。我是对的吗?
有没有办法做到这一点,还是Spring提供了任何其他方式来在运行时切换数据库?
我发现了这篇文章Dynamic DataSource Routing,但这篇帖子很老,而且在这篇文章中也没有使用过JPA。请帮助
感谢。
修改 --------------------------------
@Lazy
@Service("dbManager")
@Repository
@Transactional
public class DatabaseManager {
public enum EnumLmsPlateform {
MODERN,
LEGACY;
}
private EnumLmsPlateform lmsPlatform;
public EnumLmsPlateform getLmsPlatform() {
return lmsPlatform;
}
public void setLmsPlatform(EnumLmsPlateform lmsPlatform) {
this.lmsPlatform = lmsPlatform;
}
@PostConstruct
public void init() {
setLmsPlatform(EnumLmsPlateform.MODERN);
}
@PersistenceContext(unitName="legacy_emf")
private EntityManager legacyEm;
@PersistenceContext(unitName="modern_emf")
private EntityManager ls360Em;
@SuppressWarnings("unchecked")
@Transactional(readOnly=true)
public List<Object> getResultList(String query, Class<?> mappingClass) throws Exception {
EntityManager em = null;
if (lmsPlatform == EnumLmsPlateform.LEGACY) {
em = legacyEm;
} else if (lmsPlatform == EnumLmsPlateform.MODERN){
em = ls360Em;
}
Query emQuery = em.createNativeQuery(query, mappingClass);
return emQuery.getResultList();
} //end of findTraineeFromLegacy()
} //end of class
这是我的春季档案
遗留-spring.xml
<bean id="legacyDataSource" name="legacy_DataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" lazy-init="true">
<property name="driverClassName" value="${jdbc.legacy.driverClassName}" />
<property name="url" value="${jdbc.legacy.url}" />
<property name="username" value="${jdbc.legacy.username}" />
<property name="password" value="${jdbc.legacy.password}" />
</bean>
<bean id="legacyTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" lazy-init="true">
<property name="entityManagerFactory" ref="legacyEmf"/>
</bean>
<tx:annotation-driven transaction-manager="legacyTransactionManager" />
<bean id="legacyEmf" name="legacy_emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" lazy-init="true" >
<property name="dataSource" ref="legacyDataSource" />
<property name="jpaVendorAdapter" ref="vendorAdaptor" />
<property name="packagesToScan" value="com.softech.ls360.integration.regulators.plcb.domain"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
相同的文件适用于moderns-spring.xml
然后我将这两个文件都包含在我的maim spring中
APP-context.xml中
<import resource="classpath:database/hibernate-context.xml"/>
<import resource="classpath:database/legacyJpa-context.xml"/>
<import resource="classpath:database/modernJpa-context.xml"/>
<context:annotation-config/>
....
但这个设计中有一个流程。两位经理都包括在内。遗产与现代。我的意思是当我的dbManager bean初始化时,它需要@PersistenceContext(unitName="legacy_emf"), @PersistenceContext(unitName="modern_emf")
。应该发生什么,因为我的默认persistence context
是现代的,所以只有@PersistenceContext(unitName="modern_emf")
这个持久化上下文应该在bean初始化时可用。然后,如果我设置enum to legacy
然后unitName="legacy_emf"
,那么这应该可用。你找到了我吗?
由于
编辑2: -------------------------------------------------- -------------------
我在下面更改了我的dbManager类
@Lazy
@Service("dbManager")
@Repository
@Transactional
public class DatabaseManager {
public enum EnumLmsPlateform {
MODERN,
LEGACY;
}
private EnumLmsPlateform lmsPlatform;
public DatabaseManager() {
}
@PostConstruct
public void init() {
setLmsPlatform(EnumLmsPlateform.MODERN);
}
public EnumLmsPlateform getLmsPlatform() {
return lmsPlatform;
}
public void setLmsPlatform(EnumLmsPlateform lmsPlatform) {
this.lmsPlatform = lmsPlatform;
}
@ModernTx
public List<Object> getModernResultSet(String query, Class<?> mappingClass) {
EntityManager modernEm = getEntityManagerFormBoundTransactionalThread();
return getResultSet(modernEm, query, mappingClass);
}
@LegacyTx
public List<Object> getLegacyResultSet(String query, Class<?> mappingClass) {
EntityManager legacyEm = getEntityManagerFormBoundTransactionalThread();
return getResultSet(legacyEm, query, mappingClass);
}
@Transactional
public List<Object> getDefaultResultSet(String query, Class<?> mappingClass) {
EntityManager defaultEm = getEntityManagerFormBoundTransactionalThread();
return getResultSet(defaultEm, query, mappingClass);
}
private List<Object> getResultSet(EntityManager em, String query, Class<?> mappingClass) {
Query emQuery = em.createNativeQuery(query, mappingClass);
return emQuery.getResultList();
}
private EntityManager getEntityManagerFormBoundTransactionalThread(){
Map<Object, Object> map = TransactionSynchronizationManager.getResourceMap();
for (Object value :map.values()) {
if(value instanceof EntityManagerHolder){
return ((EntityManagerHolder)value).getEntityManager();
}
}
return null;
} //end of getEntityManagerFormBoundTransactionalThread()
} //end of class
我的考试班
public class TestDynamicJpa {
String springXmlFile = "classpath:spring/app-context-xml.xml";
GenericXmlApplicationContext springContext = SpringUtil.loadSpringContext(springXmlFile);
List<Object> traineeList = getLegacyResultList(springContext);
private List<Object> getLegacyResultList(GenericXmlApplicationContext springContext) throws Exception {
DatabaseManager dbManager = springContext.getBean("dbManager", DatabaseManager.class);
List<Object> resultList = dbManager.getLegacyResultSet(FIND_TRAINEE_LEGACY, LegacyTrainee.class);
return resultList;
} //end of getLegacyResultList()
} //end of class TestDynamicJpa
一个问题。当我做的时候
List<Object> resultList = dbManager.getLegacyResultSet(FIND_TRAINEE_LEGACY, LegacyTrainee.class);
然后从地图中获取LegacyTransactionManager
,很好。但如果我这样做
List<Object> resultList = dbManager.getDefaultResultSet(FIND_TRAINEE_LEGACY, LegacyTrainee.class);
然后从Map获取哪个事务管理器。 Legacy
或Modern
?
我也用这个配置检查了
<import resource="classpath:database/hibernate-context.xml"/>
<import resource="classpath:database/legacyJpa-context.xml"/>
<!--
<import resource="classpath:database/ls360Jpa-context.xml"/>
-->
即,只导入一个Jpa上下文,它工作正常:)。使用我以前的@PersistenceUnit
配置时,如果我注释掉一个文件,我会收到错误:)。
谢谢:)
答案 0 :(得分:0)
在这种情况下,由于还有2个数据源,您应该创建另外2个具有不同名称的transactionManager。
<bean id="legacyTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emfLegacy"/>
</bean>
<bean id="modernTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emfModern"/>
</bean>
<bean id="emfLegacy" name="myEmfLegacy" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" lazy-init="true">
<property name="dataSource" ref="legacyDataSource" />
<property name="jpaVendorAdapter" ref="vendorAdaptor" />
<property name="packagesToScan" value="com.softech.ls360.integration.regulators.plcb.domain"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="emfModern" name="myEmfModern" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" lazy-init="true">
<property name="dataSource" ref="modernDataSource" />
<property name="jpaVendorAdapter" ref="vendorAdaptor" />
<property name="packagesToScan" value="com.softech.ls360.integration.regulators.plcb.domain"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional("modernTransactionManager")
public @interface ModernTx {
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional("legacyTransactionManager")
public @interface LegacyTx {
}
之后,其余的很简单,只需使用@ModernTx或@LegacyTx注释bean的db方法,如下所示。
public class TransactionalService {
@ModernTx
public void setSomething(String name) {
EntityManager currentEm = getEntityManagerFormBoundTransactionalThread();
/*You can do anything with this Modern em*/
}
@LegacyTx
public void doSomething() {
EntityManager currentEm = getEntityManagerFormBoundTransactionalThread();
/*You can do anything with this Legacy em*/
}
@Transactional
public void buySomething() {
EntityManager currentEm = getEntityManagerFormBoundTransactionalThread();
/*You can do anything with this default em*/
}
private getEntityManagerFormBoundTransactionalThread(){
Map<Object, Object> map = TransactionSynchronizationManager.getResourceMap();
for (Object value :map.values()) {
if(value instanceof EntityManagerHolder){
return ((EntityManagerHolder)value).getEntityManager();
}
}
}
}
但是,如果您希望使用dafult数据源,只需使用@Transactional,因为您已在上下文中配置了默认事务管理器。