动态更改Spring数据源

我有一个Spring应用程序,我想动态更改数据源。当输入DS URL时,Spring Bean和所有依赖项将自动更新。我知道这有些奇怪,但是无论如何我都想实现。我的Spring配置如下:


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

问题是:


JDBC URL存储在属性中,可以在运行时更改。


更改URL后,我需要重新创建数据源,可能还需要重新创建相关对象。我不知道如何在春季优雅地做它?


我知道Spring确实可以基于一个键动态路由数据源,但是数据源URL是在Spring中预定义的,不会更改运行时。这不是我的情况。


犯罪嫌疑人X
浏览 452回答 3
3回答

炎炎设计

您可以通过扩展spring 并覆盖应该返回引用要使用的数据源spring bean的键的方法来使用spring的AbstractRoutingDataSourcedetermineCurrentLookupKey()。在spring source的博客上看一下这篇博客文章,它将向您展示如何使用该功能的示例。基本上要回答您的问题,您需要做的是在XML配置中将两个数据源定义为不同的spring bean。无需动态创建一个,spring会同时加载两者,并根据determineCurrentLookupKey()方法中的条件动态使用一个或另一个。这将导致类似:XML配置<!-- first data source --><bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">&nbsp; &nbsp; <property name="serverName" value="${jdbc.major.serverName}" />&nbsp; &nbsp; <property name="portNumber" value="${jdbc.major.portNumber}" />&nbsp; &nbsp; <property name="user" value="${jdbc.major.username}" />&nbsp; &nbsp; <property name="password" value="${jdbc.major.password}" />&nbsp; &nbsp; <property name="databaseName" value="${jdbc.major.databaseName}" /></bean><!-- second data source --><bean id="minorDataSource" class="org.postgresql.ds.PGSimpleDataSource">&nbsp; &nbsp; <property name="serverName" value="${jdbc.minor.serverName}" />&nbsp; &nbsp; <property name="portNumber" value="${jdbc.minor.portNumber}" />&nbsp; &nbsp; <property name="user" value="${jdbc.minor.username}" />&nbsp; &nbsp; <property name="password" value="${jdbc.minor.password}" />&nbsp; &nbsp; <property name="databaseName" value="${jdbc.minor.databaseName}" /></bean><!-- facade data source --><bean id="dataSource" class="blog.datasource.CustomerRoutingDataSource">&nbsp; &nbsp;<property name="targetDataSources">&nbsp; &nbsp; &nbsp; <map>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<entry key="MINOR" value-ref="minorDataSource"/>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<entry key="MAJOR" value-ref="majorDataSource"/>&nbsp; &nbsp; &nbsp; </map>&nbsp; &nbsp;</property>&nbsp; &nbsp;<property name="defaultTargetDataSource" ref="majorDataSource"/></bean><!-- wiring up --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">&nbsp; &nbsp; <property name="dataSource" ref="dataSource"/></bean><tx:annotation-driven transaction-manager="transactionManager"/><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">&nbsp; &nbsp; <property name="dataSource" ref="dataSource"/>&nbsp; &nbsp; <property name="configLocation" value="classpath:sqlmap-config.xml"/></bean>爪哇public class MyRoutingDataSource extends AbstractRoutingDataSource {&nbsp; &nbsp;@Override&nbsp; &nbsp;protected Object determineCurrentLookupKey() {&nbsp; &nbsp; &nbsp; // get the current url&nbsp; &nbsp; &nbsp; HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();&nbsp; &nbsp; &nbsp; if (request.getRequestURL().toString().endsWith("/minor"))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return "MINOR";&nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return "MAJOR";&nbsp; &nbsp;}}

德玛西亚99

我不确定这是否是正确的方法,但是您可以做的是这样的事情。<bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">&nbsp; &nbsp; <property name="serverName" value="dummydata" />&nbsp; &nbsp; <property name="portNumber" value="dummydata" />&nbsp; &nbsp; <property name="user" value="dummydata" />&nbsp; &nbsp; <property name="password" value="dummydata" />&nbsp; &nbsp; <property name="databaseName" value="dummydata" /></bean><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">&nbsp; &nbsp; <property name="dataSource" ref="majorDataSource"/></bean><tx:annotation-driven transaction-manager="transactionManager"/>并且在Java类中public class TestTransaction {&nbsp; &nbsp;@Autowired&nbsp; &nbsp;private DataSourceTransactionManager manager;&nbsp; &nbsp;private PlatformTransactionManager transactionManager;&nbsp; &nbsp;public testExecution(DataSource ds) {&nbsp; &nbsp; &nbsp; &nbsp;manager.setDataSource(ds);&nbsp; &nbsp; &nbsp; &nbsp;transactionManager = manager;&nbsp; &nbsp; &nbsp; &nbsp;TransactionDefinition def = new DefaultTransactionDefinition();&nbsp; &nbsp; &nbsp; &nbsp;TransactionStatus status = transactionManager.getTransaction(def);&nbsp; &nbsp; &nbsp; &nbsp;try {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;jdbcTemplate.update();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;transactionManager.commit(status);&nbsp; &nbsp; &nbsp; &nbsp;} catch (Exception ex) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;transactionManager.rollback(status);&nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp;}}请建议这种方法是否可以工作,因为我还是Spring的新手

慕尼黑的夜晚无繁华

我使用主要数据库和次要数据库进行故障转移。当主要数据库失败时,我将提升次要数据库为主要数据库。然后,我需要设置第三个数据库作为备用数据库,其URL将是动态的,无法在此处预定义。无论如何,也许我可以强制对主要数据库和次要数据库使用静态IP,因此无需动态更改URL。
打开App,查看更多内容
随时随地看视频慕课网APP