动态切换mysql数据源_AbstractRoutingDataSource动态切换数据源

一:流程图解

灵活动态的切换数据源,每次在执行一个Dao操作之前可以设置当前的数据源。

二:实现原理

1、扩展Spring的AbstractRoutingDataSource抽象类(该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上。)

从AbstractRoutingDataSource的源码中

我们可以看到,它继承了AbstractDataSource,而AbstractDataSource不就是javax.sql.DataSource的子类,So我们可以分析下它的getConnection方法:

获取连接的方法中,重点是determineTargetDataSource()方法,看源码:

上面这段源码的重点在于determineCurrentLookupKey()方法,这是AbstractRoutingDataSource类中的一个抽象方法,而它的返回值是你所要用的数据源dataSource的key值,有了这个key值,

resolvedDataSource(这是个map,由配置文件中设置好后存入的)就从中取出对应的DataSource,如果找不到,就用配置默认的数据源。

看完源码,应该有点启发了吧,没错!你要扩展AbstractRoutingDataSource类,并重写其中的determineCurrentLookupKey()方法,来实现数据源的切换:

public class DynamicDataSource extendsAbstractRoutingDataSource {/*** override determineCurrentLookupKey

* Description: 自动查找datasource*/@OverrideprotectedObject determineCurrentLookupKey() {//从自定义的位置获取数据源标识

returnDynamicDataSourceHolder.getDataSource();

}

}

DynamicDataSourceHolder这个类则是我们自己封装的对数据源进行操作的类:

public classDynamicDataSourceHolder {/*** 注意:数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰*/

private static final ThreadLocal THREAD_DATA_SOURCE = new ThreadLocal();

//获取数据源public staticString getDataSource() {returnTHREAD_DATA_SOURCE.get();

}

//设置数据源public static voidsetDataSource(String dataSource) {

THREAD_DATA_SOURCE.set(dataSource);

}

//清空数据源public static voidclearDataSource() {

THREAD_DATA_SOURCE.remove();

}

}

那么setDataSource方法要在什么地方执行呢?

我们可以应用Spring aop来设置,把配置的数据源类型都设置成注解标签,在Servive层中需要切换数据源的方法上,写上注解标签,调用相应的方法切换数据源

@DataSource(name=DataSource.slave1)public List getProducts(){

import java.lang.annotation.*;

@Target({ElementType.METHOD,ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documentedpublic @interfaceDataSource{

String name()defaultDataSource.master;public static String master="datasource1";public static String slave1="datasource2";

publidstatic String slave2="datasource3";

}

三:配置文件

项目中单独分离出application-database.xml,关于数据源配置的文件

配置多数据源映射关系

SessionFactory的配置还是照旧,使用以前的配置,只不过当前选择的数据源是datasource,也就是数据源选择的中间层MultipleDataSourceToChoose,因为当前的中间层中实现了DataSource这个接口,所以可以看做为DataSource的是实现类啦,所以配置不会出现问题。

使用AOP拦截特定的注解去动态的切换数据源

@Order(1)如果有多个拦截器时,第一个执行

@Aspect

@Slf4j

@Component

@Order(1)public classDataSourceAop {//@within在类上进行设置//@annotation 在方法上进行设置

@Pointcut("@within(com.zmeng.rinascimento.caravaggio.common.util.datasource.DataSource)||@annotation(com.zmeng.rinascimento.caravaggio.common.util.datasource.DataSource)")public voidpointcut(){}

@Before("pointcut()")public void doBefore(JoinPoint joinPoint)throwsException{

Class clazz=joinPoint.getTarget().getClass();

String methodName=joinPoint.getSignature().getName();

Class[] parameterTypes=((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes();

Method method=clazz.getMethod(methodName,parameterTypes);//获取方法上的注解

DataSource dataSource = method.getAnnotation(DataSource.class);if(dataSource==null){//获取类上的注解

dataSource = joinPoint.getTarget().getClass().getAnnotation(DataSource.class);if(dataSource==null){return;

}

}//获取注解上的数据源信息

String dataSourceKey =dataSource.value();if(dataSourceKey!=null){//给当前执行SQL操作设置特殊的数据源的信息

DynamicDataSourceHolder.setDataSource(dataSourceKey);

System.out.println(DynamicDataSourceHolder.getDataSource());

}

log.info("AOP动态切换数据源,className"+joinPoint.getTarget().getClass().getName()+"methodName"+method.getName()+";dataSourceKey:"+dataSourceKey==""?"默认数据源":dataSourceKey);

}

@After("pointcut()")public voidafter(JoinPoint joinPoint){//清理掉当前的数据源,让默认的数据不受影响

System.out.println(DynamicDataSourceHolder.getDataSource());

DynamicDataSourceHolder.clearDataSource();

}

}

如果不使用aop进行拦截切换数据源,也可以在代码中进行手动的切换数据源

DynamicDataSourceHolder.setDataSource("dataSource");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值