基于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. As I Began to Love Myself

    As I Began to Love Myself: Charlie Chaplin on his 70th birthday As I began to love myself I found th ...

  2. c 字符串的结束标志

    //char carray[]="nihao"; char carray[]={'a','b','c','d','\0'}; printf("array=%s" ...

  3. [TJOI2019]甲苯先生的滚榜——非旋转treap

    题目链接: [TJOI2019]甲苯先生的滚榜 要求维护一个二维权值的集合并支持单点修改,用平衡树维护即可. 因为$n\le 10^6$但$m\le 10^5$,所以最多只有$10^5$个人被操作. ...

  4. 4)抽象方法不能为private,final或者static,为什么?

    抽象方法的最实质的意 义在于被未来的子类覆盖实现掉.它自己是个空方法.private的实质意义在于本类其他方法调用它.你自己是个空方法,别人调用你有什么用?所以 abstract和private在一起 ...

  5. Java实现通过IP获取域名,通过域名获取IP

    一.通过Linux命令实现 ping www.baidu.com nslookup www.baidu.com nslookup 14.215.177.166 为什么这个命令会有一个192.168.1 ...

  6. Ideal打war包和tomcat展示War包

    今天主要是介绍如何把java代码把成war包以及如何在tomcat中放置展示.比较简单.大家可以看看 刚开始ideal 不知道打包,网上搜索了一个教程,看了半天没看会. 主要还是说的不太明白 . 不过 ...

  7. 2.linux的增删改查

    一.增删改查       1.建立文件和目录         mkdir /tmp/xueying       2.cd 进入的路径         绝对路径:以根目录为其实目录的路径         ...

  8. IDEA使用(03)_git撤回(已经commit未push的)操作

    1.问题来源 日常工作中会遇到 commit 到本地仓库的代码,因为一些原因,需要撤销后再提交到本地,或者需要整合多次 commit,然后 push 到远程仓库. 2.IDEA解决方案 I.在idea ...

  9. Mysql --- Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause

    我使用的5.5的mysql数据库会报这个错, 换成5.7的就可以了

  10. CardView 简介和使用

    CardView 简介 本文链接:https://blog.csdn.net/ShawnXiaFei/article/details/81568537CardView 是 Google 官方发布 MD ...