spring动态切换数据源配置

最近接触了一个项目需要夸库取数据,起初使用spring的jdbctemplate去查询数据,后来觉得这种方式太low,于是在空闲期间就摸索尝试一下动态配置切换数据源,在此记录一下便于以后学习使用:

版权声明:本文为博主原创文章,未经博主允许不得转载。

spring已经为我们封装了AbstractRoutingDataSource接口便于切换数据源,我们只要继承此类用于获取数据源

 

首先需要在spring配置文件中配置多数据源加入以下配置

 

<!-- 数据源配置, 使用Tomcat JDBC连接池 -->
        <bean id="dataSource1" class="org.apache.tomcat.jdbc.pool.DataSource"
            destroy-method="close">
            <!-- Connection Info -->
            <property name="driverClassName" value="${jdbc.driver}" />
            <property name="url" value="${jdbc.url}" />
            <property name="username" value="${jdbc.username}" />
            <property name="password">
                <bean factory-method="decryptPassword"
                    class="com.qware.platform.framework.utils.ConfigUtil">
                    <constructor-arg value="${jdbc.pword}" />
                </bean>
            </property>
            <property name="validationQuery" value="SELECT 1" />
            <!-- Connection Pooling Info -->
            <property name="maxActive" value="${jdbc.pool.maxActive}" />
            <property name="maxIdle" value="${jdbc.pool.maxIdle}" />
            <property name="minIdle" value="0" />
            <property name="defaultAutoCommit" value="false" />
        </bean>
        
        <bean id="dataSource2" class="org.apache.tomcat.jdbc.pool.DataSource"
            destroy-method="close">
            <!-- Connection Info -->
            <property name="driverClassName" value="${jdbc2.driver}" />
            <property name="url" value="${jdbc2.url}" />
            <property name="username" value="${jdbc2.username}" />
            <property name="password">
                <bean factory-method="decryptPassword"
                    class="com.qware.platform.framework.utils.ConfigUtil">
                    <constructor-arg value="${jdbc2.pword}" />
                </bean>
            </property>
            <property name="validationQuery" value="SELECT 1" />
            <!-- Connection Pooling Info -->
            <property name="maxActive" value="${jdbc2.pool.maxActive}" />
            <property name="maxIdle" value="${jdbc2.pool.maxIdle}" />
            <property name="minIdle" value="0" />
            <property name="defaultAutoCommit" value="false" />
        </bean>
        <bean id="dataSource" class="cn.com.citycloud.delivery.bdp.datasource.config.RoutingDataSource">
        <!-- 为targetDataSources注入两个数据源 -->
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry key="ds1" value-ref="dataSource1"/>
                <entry key="ds2" value-ref="dataSource2"/>
            </map>
        </property>
        <!-- 为指定数据源RoutingDataSource注入默认的数据源-->
         <property name="defaultTargetDataSource" ref="dataSource1"/>

 

 

 

   1. public class RoutingDataSource extends AbstractRoutingDataSource  {

     @Override
     protected Object determineCurrentLookupKey() {
           return DataSourceHolder.getDataSourceType();
     }

}

2.再来一个DataSourceHolder 用本地线程用于设置数据源

public class DataSourceHolder {
    

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); 
    
    private static Logger logger = LoggerFactory.getLogger(DataSourceHolder.class);

    /**
     * @Description: 设置数据源类型
     * @param dataSourceType  数据库类型
     * @return void
     * @throws
     */ 
    public static void setDataSourceType(String dataSourceType) { 
        
        logger.debug("当前切换数据源为"+dataSourceType);
        
        contextHolder.set(dataSourceType); 
    } 

    /**
     * @Description: 获取数据源类型
     * @param 
     * @return String
     * @throws
     */ 
    public static String getDataSourceType() { 
        return contextHolder.get(); 
    } 

    /**
     * @Description: 清除数据源类型
     * @param 
     * @return void
     * @throws
     */ 
    public static void clearDataSourceType() { 
        contextHolder.remove(); 
    }
    
}

3.利用切面Aspect 切点拦截使用到注解的方法

@Order(1)
@Aspect  
@Component
public class DataSourceAspect {
 
@Pointcut("@within(cn.com.citycloud.delivery.bdp.datasource.config.DataSource)||@annotation(cn.com.citycloud.delivery.bdp.datasource.config.DataSource)")
    private void anyMethod() {  
    }
    
    /**
     * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
     * 
     * @param point
     * @throws Exception
     */
    @Before(value="anyMethod()")
    public void intercept(JoinPoint point) throws Exception {
        String dataSource = DataSources.ds1;
        try {
            // 获得当前访问的class
            Class<?> curClass = point.getTarget().getClass();

            // 获得访问的方法名
            String methodName = point.getSignature().getName();
            // 得到方法的参数的类型
            Class<?>[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();
            // 得到访问的方法对象
            Method method = curClass.getMethod(methodName, argClass);
            // 判断方法是否存在@DataSource注解
            if (method.isAnnotationPresent(DataSource.class)) {
                DataSource methodAnnotation = method.getAnnotation(DataSource.class);
                // 取出注解中的数据源名
                dataSource = methodAnnotation.value();
            } 
            else {
                // 判断是否存在@DataSource注解
                if (curClass.isAnnotationPresent(DataSource.class)) {
                    DataSource classAnnotation = curClass.getAnnotation(DataSource.class);
                    // 取出注解中的数据源名
                    dataSource = classAnnotation.value();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 切换数据源
        DataSourceHolder.setDataSourceType(dataSource);
        
    }
     @AfterReturning(value = "anyMethod()", returning = "result")  
    public void afterReturning() {
         //DataSourceHolder.clearDataSourceType();
         DataSourceHolder.setDataSourceType(DataSources.ds1);
    }
   
 
}

4.写一个注解用于动态切换

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface DataSource {

    String value() default "ds1";

}

5.在使用时在service实现类里面的方法上

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值