2013-07-24 48 views
0

我正在使用spring 3.2.3和JPA 2.0。我想动态连接我的数据库基于枚举。我有这样如何使用Spring 3.2和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" /> 

。我对吗 ?

有没有办法做到这一点,或者是春天提供任何其他方式来切换运行时数据库?

我发现这篇文章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> 

同一个文件是现代人,spring.xml

那么我既包括文件在我的残废春天

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: ------------------------------------ ---------------------------------

我改变了下面

@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 
我dbManager类

我的测试分类

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

然后哪个事务管理器它从地图。 LegacyModern

而且我这个配置也

<import resource="classpath:database/hibernate-context.xml"/> 
<import resource="classpath:database/legacyJpa-context.xml"/> 
<!-- 
<import resource="classpath:database/ls360Jpa-context.xml"/> 
--> 

即进口只有一个JPA的情况下检查了它,并且它的正常工作:)。虽然与我以前的@PersistenceUnit配置我得到错误,如果我注释掉一个文件:)。

谢谢:)

回答

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的数据库方法如下。

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因为你已经在你的情况下,如下配置的默认事务管理器。

+0

您好感谢。请检查我的编辑。我已经完成了你所说的话。你能否向我解释一下'@ ModernTx'和'@ LegacyTx'这些注释是什么。他们是否基于枚举切换? – Basit

+0

我已经reedit我的回答 –

+0

是解决了你的问题? –

相关问题