web-dev-qa-db-fra.com

modifier dynamiquement la source de données Spring

J'ai une application Spring, je veux changer dynamiquement la source de données, ie. lors de la saisie d'une URL DS, les beans Spring et toutes les dépendances seront mis à jour automatiquement. Je sais que c'est quelque peu étrange, mais de toute façon je veux y parvenir. Ma configuration Spring comme suit:

<bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
    <property name="serverName" value="${jdbc.serverName}" />
    <property name="portNumber" value="${jdbc.portNumber}" />
    <property name="user" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="databaseName" value="${jdbc.databaseName}" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="majorDataSource"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="majorDataSource"/>
    <property name="configLocation" value="classpath:sqlmap-config.xml"/>
</bean>

Les questions sont:

  1. L'URL JDBC est stockée dans des propriétés, qui peuvent être modifiées lors de l'exécution.

  2. Une fois l'URL modifiée, j'ai besoin de recréer la source de données et peut-être les objets dépendants. Je ne pouvais pas comprendre comment le faire avec élégance au printemps?

Je savais que Spring ne pouvait acheminer dynamiquement la source de données sur la base d'une seule clé, mais l'URL de la source de données est prédéfinie dans Spring et ne changera pas l'exécution. Ce n'est pas mon cas.

29
Simon Wang

Vous pouvez utiliser le ressort AbstractRoutingDataSource en l'étendant et en remplaçant la méthode determineCurrentLookupKey() qui doit renvoyer la clé faisant référence au bean spring du source de données à utiliser.

Jetez un œil à ceci article de blog sur le blog de Spring Source qui vous montrera un exemple d'utilisation de cette fonctionnalité.

Fondamentalement, pour répondre à vos questions, vous devrez définir les deux sources de données en tant que bean Spring différent dans votre configuration XML. Il n'est pas nécessaire d'en créer un dynamiquement, spring chargera les deux et utilisera l'un ou l'autre dynamiquement en fonction de vos critères dans la méthode determineCurrentLookupKey().

Cela conduirait à quelque chose comme:

Configuration XML

<!-- first data source -->
<bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
    <property name="serverName" value="${jdbc.major.serverName}" />
    <property name="portNumber" value="${jdbc.major.portNumber}" />
    <property name="user" value="${jdbc.major.username}" />
    <property name="password" value="${jdbc.major.password}" />
    <property name="databaseName" value="${jdbc.major.databaseName}" />
</bean>
<!-- second data source -->
<bean id="minorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
    <property name="serverName" value="${jdbc.minor.serverName}" />
    <property name="portNumber" value="${jdbc.minor.portNumber}" />
    <property name="user" value="${jdbc.minor.username}" />
    <property name="password" value="${jdbc.minor.password}" />
    <property name="databaseName" value="${jdbc.minor.databaseName}" />
</bean>
<!-- facade data source -->
<bean id="dataSource" class="blog.datasource.CustomerRoutingDataSource">
   <property name="targetDataSources">
      <map>
         <entry key="MINOR" value-ref="minorDataSource"/>
         <entry key="MAJOR" value-ref="majorDataSource"/>
      </map>
   </property>
   <property name="defaultTargetDataSource" ref="majorDataSource"/>
</bean>
<!-- wiring up -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:sqlmap-config.xml"/>
</bean>

Java

public class MyRoutingDataSource extends AbstractRoutingDataSource {
   @Override
   protected Object determineCurrentLookupKey() {
      // get the current url
      HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
      if (request.getRequestURL().toString().endsWith("/minor"))
          return "MINOR";
      else
          return "MAJOR";
   }
}
30
Alex

Je ne sais pas si c'est la bonne façon de procéder, mais ce que vous pouvez faire, c'est quelque chose comme ça.

<bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
    <property name="serverName" value="dummydata" />
    <property name="portNumber" value="dummydata" />
    <property name="user" value="dummydata" />
    <property name="password" value="dummydata" />
    <property name="databaseName" value="dummydata" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="majorDataSource"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

et dans Java Class

public class TestTransaction {

   @Autowired
   private DataSourceTransactionManager manager;

   private PlatformTransactionManager transactionManager;

   public testExecution(DataSource ds) {
       manager.setDataSource(ds);
       transactionManager = manager;
       TransactionDefinition def = new DefaultTransactionDefinition();
       TransactionStatus status = transactionManager.getTransaction(def);
       try {
           jdbcTemplate.update();
           transactionManager.commit(status);
       } catch (Exception ex) {
           transactionManager.rollback(status);
       }
   }
}

Veuillez suggérer si cette approche pourrait fonctionner car je suis encore nouveau au printemps

0
Jashan Preet