Spring MVC 动态切换数据库

项目中遇到需要动态切换数据库的需求,在特定的界面需要去另外一个数据库查询信息
直接上代码
1.新建DataSourceType .java(配置数据库名称)

package com.grand.datasourse;
/**
 * 数据库名称 -需要合配置文件里的名称一致
 * @author 
 *
 * @time 2017年10月23日
 */
public class DataSourceType {

    public static final String SOURCE_UWP = "uwp_dbsourse";//主数据库
    public static final String SOURCE_WD = "wd_dbsourse";//从数据库

}

2.新建DataSourceContextHolder .java 切换数据库的类

package com.grand.datasourse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 
 * @author  数据库切换的工具类:切换数据库
 * 
 * @time 2017年10月22日
 */
public class DataSourceContextHolder {
    //线程局部变量
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
    private static final Logger LOG = LoggerFactory
            .getLogger(DataSourceContextHolder.class);
    /**
     * 提供给AOP去设置当前的线程的数据源的信息
     * 切换数据库
     * @param dbType 数据库名-配置文件中一致
     */
    public static void setDbType(String dbType) {
        try {
            contextHolder.set(dbType);
        } catch (Exception e) {
            // TODO: handle exception
            LOG.debug("ERROR____DB_Exception");
            LOG.debug(e.getMessage());
        }

    }

    /**
     * 提供给AbstractRoutingDataSource的实现类,通过key选择数据源
     * @return java.lang.String
     */
    public static String getDbType() {
        String dataSourse  =  contextHolder.get();

        if(null == dataSourse){

            DataSourceContextHolder.setDbType(DataSourceType.SOURCE_UWP);
        }

        return  contextHolder.get();
    }

    /**
     * 使用默认的数据源
     */
    public static void clearDbType() {
        contextHolder.remove();
    }
}

3.新建DynamicDataSource.java 数据源配置

package com.grand.datasourse;

import java.util.logging.Logger;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * descrption: 多数据源的选择
 * @author 
 *  AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是实现数据源的route的核心
 *               .需要重写该方法
 * @time 2017年10月22日
 */
public class DynamicDataSource extends AbstractRoutingDataSource{

    @Override  
    public Logger getParentLogger() {  
           return null;  
    }  

    @Override  
    protected Object determineCurrentLookupKey() {  
           return DataSourceContextHolder.getDbType();//获取数据源  
    } 

}

4.applicationContext.xml 里配置数据源

<!--主库-->
<bean id ="uwp_dbsourse" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">  
          <property name="driverClass" value="${jdbc.driverClassName2}" />
        <property name="jdbcUrl" value="${jdbc.url2}" />
        <property name="user" value="${jdbc.userDS.username2}" />
        <property name="password" value="${jdbc.userDS.password2}" />
        <!-- 连接池中保留的最小连接数    -->
        <property name="minPoolSize" value="1" />
        <!-- 连接池中保留的最大连接数    -->
        <property name="maxPoolSize" value="200" />
        <!-- 最大空闲时间,1800秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0-->
        <property name="maxIdleTime" value="1800" />
        <!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3-->
        <property name="acquireIncrement" value="5" />
        <!-- 最大的PreparedStatement的数量    -->
        <property name="maxStatements" value="1000" />
        <!-- 每60秒检查所有连接池中的空闲连接。Default: 0 -->
        <property name="idleConnectionTestPeriod" value="60" />
        <!-- 定义在从数据库获取新连接失败后重复尝试的次数。Default: 30-->
        <property name="acquireRetryAttempts" value="30" />
        <property name="breakAfterAcquireFailure" value="true" />
        <property name="testConnectionOnCheckout" value="false" />
   </bean > 
   <!--从库--> 
   <bean id ="wd_dbsourse" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">  
          <property name="driverClass" value="${jdbc.driverClassName1}" />
        <property name="jdbcUrl" value="${jdbc.url1}" />
        <property name="user" value="${jdbc.userDS.username1}" />
        <property name="password" value="${jdbc.userDS.password1}" />
        <!-- 连接池中保留的最小连接数    -->
        <property name="minPoolSize" value="1" />
        <!-- 连接池中保留的最大连接数    -->
        <property name="maxPoolSize" value="200" />
        <!-- 最大空闲时间,1800秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0-->
        <property name="maxIdleTime" value="1800" />
        <!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3-->
        <property name="acquireIncrement" value="5" />
        <!-- 最大的PreparedStatement的数量    -->
        <property name="maxStatements" value="1000" />
        <!-- 每60秒检查所有连接池中的空闲连接。Default: 0 -->
        <property name="idleConnectionTestPeriod" value="60" />
        <!-- 定义在从数据库获取新连接失败后重复尝试的次数。Default: 30-->
        <property name="acquireRetryAttempts" value="30" />
        <property name="breakAfterAcquireFailure" value="true" />
        <property name="testConnectionOnCheckout" value="false" />
   </bean > 

    <!-- 动态配置数据源 -->  
   <bean id ="dataSource" class= "com.grand.datasourse.DynamicDataSource" >  
          <property name ="targetDataSources">  
                <map key-type ="java.lang.String">  
                      <entry value-ref ="wd_dbsourse" key= "wd_dbsourse"></entry >  
                      <entry value-ref ="uwp_dbsourse" key= "uwp_dbsourse"></entry >  
                </map >  
          </property >  
          <property name ="defaultTargetDataSource" ref= "uwp_dbsourse"></property >      <!-- 默认使用的数据源 -->  
   </bean > 

5.service 层调用

public List<Test> getTest(){

        List<Test> list = null;
        try {
            // 切换数据库
            DataSourceContextHolder.setDbType(DataSourceType.SOURCE_WD);




            list = wdFundMapper.getTest();

        } catch (Exception e) {
            e.printStackTrace();
            LOG.error(e.getMessage());
        }
        DataSourceContextHolder.clearDbType();//切回主库
        return list;
    }

注意:项目中发现,这种service层调用方式,存在小瑕疵,在同一个service 中,只能调用一个库,无法进行切库操作
例如:A service中,调用主库
B service中,掉用从库
A 中调用B的方法,往往失败
本人的做法是,将调用从库的方法统一写在B中,在控制层同时调用AB方法,将数据在控制层做区分

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring提供了一种开发模式,称为面向切面编程(AOP),可以通过它来实现数据库切换。在Spring MVC中,我们可以使用AOP来拦截和修改方法的执行,以便动态切换数据库。 首先,我们需要配置Spring的AOP,以便在运行时拦截方法。这可以通过在Spring配置文件中添加以下代码来实现: ``` <aop:aspectj-autoproxy/> ``` 接下来,我们需要创建一个切面类,该类将拦截和处理我们选择的目标方法。在这个切面类中,我们可以编写切面逻辑来判断需要使用哪个数据库。下面是一个示例切面类的代码: ```java @Aspect @Component public class DatabaseSwitchAspect { @Before("execution(* com.example.controller.*.*(..))") public void switchDatabase(JoinPoint joinPoint) { // 判断需要使用哪个数据库 if (需要使用第一个数据库的条件) { // 设置第一个数据库的相关配置 DataSourceContextHolder.setDataSourceType(第一个数据库); } else { // 设置第二个数据库的相关配置 DataSourceContextHolder.setDataSourceType(第二个数据库); } } } ``` 在以上代码中,我们使用@Before注解来指定拦截哪些方法。在拦截到方法之后,我们可以在切面逻辑中根据判断条件来选择需要使用的数据库,并使用自定义的DataSourceContextHolder来动态设置数据源。 最后,我们需要在Spring配置文件中配置数据源和事务管理器。这里我们需要配置两个数据源和对应的事务管理器,以便与切面类中设置的数据源保持一致。 通过以上步骤,我们就能够实现Spring MVC中AOP的方式来动态切换数据库。当我们拦截到目标方法时,根据条件切换数据库,从而实现数据库动态切换

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值