multiples multiple datasources java spring datasource

java - datasources - spring boot multiple datasource



cambiar dinĂ¡micamente fuente de datos de primavera (2)

Tengo una aplicación Spring, quiero cambiar la fuente de datos de forma dinámica, es decir. cuando ingresamos una URL de DS, los beans de Spring y todas las dependencias se actualizarán automáticamente. Sé que esto es algo extraño, pero de todos modos quiero lograr eso. La configuración de My Spring es la siguiente:

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

Las preguntas son:

  1. La URL de JDBC se almacena en propiedades, que podrían modificarse en tiempo de ejecución.

  2. Una vez que se cambia la URL, necesito volver a crear la fuente de datos y tal vez los objetos dependientes. No pude entender cómo hacerlo elegantemente en primavera?

He sabido que Spring did podría enrutar dinámicamente la fuente de datos basada en una clave, pero la fuente de datos URL está predefinida en Spring y no cambiará el tiempo de ejecución. No es mi caso.


No estoy seguro de si esta es la forma correcta de hacerlo, pero lo que puede hacer es algo como esto.

<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"/>

y en 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); } } }

Por favor sugiera si este enfoque podría funcionar ya que todavía soy nuevo en Spring


Puede usar AbstractRoutingDataSource de Spring extendiéndolo y reemplazando el método determineCurrentLookupKey() que debe devolver la clave que hace referencia al bean de primavera del origen de datos que se utilizará.

Eche un vistazo a este artículo de blog en el blog de Spring Source que le mostrará un ejemplo de cómo usar esa característica.

Básicamente para responder a sus preguntas, lo que deberá hacer es definir las dos fuentes de datos como diferentes bean de primavera en su configuración XML. No es necesario crear uno de forma dinámica, Spring cargará ambos y utilizará uno u otro de forma dinámica según sus criterios en el método determineCurrentLookupKey() .

Esto llevaría a algo así como:

Configuración 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"; } }