为了账号安全,请及时绑定邮箱和手机立即绑定

动态更改Spring数据源

动态更改Spring数据源

犯罪嫌疑人X 2019-12-26 09:53:57
我有一个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中预定义的,不会更改运行时。这不是我的情况。
查看完整描述

3 回答

?
炎炎设计

TA贡献1808条经验 获得超4个赞

您可以通过扩展spring 并覆盖应该返回引用要使用的数据源spring bean的键的方法来使用spring的AbstractRoutingDataSourcedetermineCurrentLookupKey()。


在spring source的博客上看一下这篇博客文章,它将向您展示如何使用该功能的示例。


基本上要回答您的问题,您需要做的是在XML配置中将两个数据源定义为不同的spring bean。无需动态创建一个,spring会同时加载两者,并根据determineCurrentLookupKey()方法中的条件动态使用一个或另一个。


这将导致类似:


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>

爪哇


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

   }

}


查看完整回答
反对 回复 2019-12-26
?
德玛西亚99

TA贡献1770条经验 获得超3个赞

我不确定这是否是正确的方法,但是您可以做的是这样的事情。


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

并且在Java类中


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

       }

   }

}

请建议这种方法是否可以工作,因为我还是Spring的新手


查看完整回答
反对 回复 2019-12-26
?
慕尼黑的夜晚无繁华

TA贡献1864条经验 获得超6个赞

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

查看完整回答
反对 回复 2019-12-26
  • 3 回答
  • 0 关注
  • 449 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信