基于AbstractRoutingDataSource实现动态切换数据源

/**
 * DataSource
注解接口
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface
DataSourceAnnotation {
    String value() default DataSourceSelect.MASTER;
}

/**
 *
注解前后增强获取数据库清空数据库
 */
@Aspect
@Component
@Logger
public class DatasourceAspect {
@Pointcut("@annotation(com.example.demo.config.DataSourceAnnotation)")
public void pointcut() {
}
    @Before("pointcut()")
    public void beforeExecute(JoinPoint
joinPoint) {
        Method method =
((MethodSignature) joinPoint.getSignature()).getMethod();
        DataSourceAnnotation annotation = method.getAnnotation(DataSourceAnnotation.class);
        if (annotation == null) {
            annotation =
joinPoint.getTarget().getClass().getAnnotation(DataSourceAnnotation.class);
             DynamicDataSource.setDataSource(DataSourceSelect.MASTER);
        }else{
            // 切换数据源
            DynamicDataSource.setDataSource (annotation.value());
        }
    }
    @After("pointcut()")
    public void afterExecute() {
        DynamicDataSource.clear();
    }
}

定义数据源类来存储多个数据源选择

public interface DataSourceSelect {
    /**
     *
主库源
     */
   
String MASTER="master";
    /**
     *
从库源
     */
   
String  SLAVE ="slave";

}

继承AbstractRoutingDataSource重写方法实现把默认数据源和目标数据源注入

并提供ThreadLocal线程保证数据源隔离。

public class DynamicDataSource extends AbstractRoutingDataSource
{
    private final Logger logger = LoggerFactory.getLogger(DynamicDataSource.class);
    private static final ThreadLocal<String> DATA_SOURCE_CONTEXT_HOLDER = new ThreadLocal<>();

public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }
    @Override
    protected Object
determineCurrentLookupKey() {
        return getDataSource();
    }
     static void setDataSource(String
dataSource) {
        DATA_SOURCE_CONTEXT_HOLDER.set(dataSource);
    }

public static String getDataSource() {
        return DATA_SOURCE_CONTEXT_HOLDER.get();
    }

static void clear() {
        DATA_SOURCE_CONTEXT_HOLDER.remove();
    }

}

把数据源配置路径与数据源匹配,并利用子类调用有参构造调用父类AbstractRoutingDataSource的方法把数据源信息加载进datasource

/**
 *
配置多数据源
 * @author xiaohe
 * @version V1.0.0
 */
@Configuration
public class DynamicDataSourceConfig {

@Bean
    @ConfigurationProperties("spring.datasource.master")
    public DataSource
masterDataSource(){

return DruidDataSourceBuilder.create().build();
    }

@Bean
    @ConfigurationProperties("spring.datasource.slave")
    public DataSource
slaveDataSource(){

return DruidDataSourceBuilder.create().build();
    }
    @Bean
    @Primary
    public DynamicDataSource
dataSource(DataSource masterDataSource, DataSource
slaveDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>(5);
        targetDataSources.put(DataSourceSelect.MASTER, masterDataSource);
        targetDataSources.put(DataSourceSelect.SLAVE, slaveDataSource);
        return new DynamicDataSource(masterDataSource, targetDataSources);
    }

}

Application启动项,exclude = DataSourceAutoConfiguration.class排除自动注入数据源的配置,加上Import 用来加加载我们定义的datasource。

 
@ComponentScan(basePackages ="com.example.demo.*")
@EnableJpaRepositories("com.example.demo.repository")
@Import(DynamicDataSourceConfig.class)
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class DruidApplication {
    public static void main(String[] args) {
        SpringApplication.run(DruidApplication.class, args);
    }
}

FQA:

9. 注解没有被注入到ioc容器导致注解失效。

10. 多数据源的动态切换,在程序运行时,把数据源数据源动态织入到程序中,灵活的进行数据源切换。
- 基于多数据源的动态切换,我们可以实现读写分离,这么做缺点也很明显,无法动态的增加数据源。

只支持单库事务,也就是说切换数据源要在开启事务之前执行。

spring DataSourceTransactionManager进行事务管理,开启事务,会将数据源缓存到DataSourceTransactionObject对象中进行后续的commit rollback等事务操作。

基于AbstractRoutingDataSource实现动态切换数据源的更多相关文章

  1. AbstractRoutingDataSource 实现动态切换数据源

    扩展AbstractRoutingDataSource类 package com.datasource.test.util.database; import org.springframework.j ...

  2. Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源 方法

    一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...

  3. hibernate动态切换数据源

    起因: 公司的当前产品,主要是两个项目集成的,一个是java项目,还有一个是php项目,两个项目用的是不同的数据源,但都是mysql数据库,因为java这边的开发工作已经基本完成了,而php那边任务还 ...

  4. 在使用 Spring Boot 和 MyBatis 动态切换数据源时遇到的问题以及解决方法

    相关项目地址:https://github.com/helloworlde/SpringBoot-DynamicDataSource 1. org.apache.ibatis.binding.Bind ...

  5. Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源方法

    一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...

  6. Spring学习总结(16)——Spring AOP实现执行数据库操作前根据业务来动态切换数据源

    深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...

  7. Spring+Mybatis动态切换数据源

    功能需求是公司要做一个大的运营平台: 1.运营平台有自身的数据库,维护用户.角色.菜单.部分以及权限等基本功能. 2.运营平台还需要提供其他不同服务(服务A,服务B)的后台运营,服务A.服务B的数据库 ...

  8. Spring动态切换数据源及事务

    前段时间花了几天来解决公司框架ssm上事务问题.如果不动态切换数据源话,直接使用spring的事务配置,是完全没有问题的.由于框架用于各个项目的快速搭建,少去配置各个数据源配置xml文件等.采用了动态 ...

  9. AOP获取方法注解实现动态切换数据源

    AOP获取方法注解实现动态切换数据源(以下方式尚未经过测试,仅提供思路) ------ 自定义一个用于切换数据源的注解: package com.xxx.annotation; import org. ...

随机推荐

  1. python 里列表 extend 与 append 的区别

    extend 只能添加以列表形式的,而 append 可以添加任何的. 来自别人家的官方句子: extend 与 append 方法的相似之处在于都是将新接收到参数放置到已有列表的后面.而 exten ...

  2. 数据结构实验之图论十一:AOE网上的关键路径【Bellman_Ford算法】

    Problem Description 一个无环的有向图称为无环图(Directed Acyclic Graph),简称DAG图.     AOE(Activity On Edge)网:顾名思义,用边 ...

  3. centos6安装Python3环境

    Python3安装 CentOS 6+系统默认安装的python版本是2.6.6,python2版本与python3还有有一些语法上的不一样.我们要把python升级到3版本,但是系统自带的旧版本py ...

  4. python版本下载时时,官方目录web-based与executable和embeddable 的区别

    背景:安装python时不知道选择哪个版本以及他们之间的意思. 1.X86和X86-64的区别:系統是32 bit 的版本还是 64bit 的 2.web-based ,executable , em ...

  5. 怎么看部分元素的js代码?

  6. jquery 性能优化高级技巧

    有时为了书写方便,忽视了程序执行中给客户端带来的压力.导致在低端浏览器的运行缓慢. 1>通过CDN引用jquery,能减少网站加载时间.http://apps.bdimg.com/libs/jq ...

  7. “可恶”的mariadb

    这是头一次用mariadb,听说是centos7自带的,本来本地用的好好地,今天想连接一下远程centos7主机上的mariadb,结果各种出错,痛不欲生,最后实在买办法只能卸载装mysql啦.稍微记 ...

  8. html5、手机端 input 单独打开相机、摄像头、录音功能

    相机:<input type="file" name="image" accept="image/*" capture="u ...

  9. python pip settools 安装基于源码 gdal安装需要c++相关库

  10. mac下PHP安装mongo扩展

    说明:mongo 和 mongodb是两个扩展,目前mongo扩展已经被废弃,建议使用mongodb扩展,但对于一些老项目还在使用mongo扩展的,请参考此文. mongodb和其他PHP扩展的安装方 ...