基于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. Java 【打印俄文的英文字母】

    俄文的的字符可以用 'A' 到 'Я '. public class main { public static void main(String args[]) { char S = 'А', C = ...

  2. 修改rabbitmq web-UI端口号

    一.拷贝配置文件 [root@test03 ~]# cd /usr/share/doc/rabbitmq-server-3.6.15/ [root@test03 rabbitmq-server-3.6 ...

  3. 对list某个条件排序,并实现分页

    package com.jcloud.aioc.api.controller.Test; import com.alibaba.fastjson.JSON; import org.apache.poi ...

  4. Codeforces - 2019年11月补题汇总

    大概目标是补到 #500 为止的 Div. 2 ,先定个小目标,寒假开始前补到 #560 为止 Codeforces Round #599 (Div. 2) 5/6 备注:0-1BFS(补图连通块) ...

  5. VS2017 怎么启用nuget程序包还原?

    以前VS2015的时候,在解决方案右键会有一个“启用nuget程序包还原”的选项. 现在换成2017了,这个选项的位置变成了“还原nuget包”,现在新建到TFS上的项目,别人下完都没法还原,求解! ...

  6. javaSE集合---进度2

    一.集合框架 1.特点 对象封装数据,对象多了也需要存储,集合用于存储对象. 对象的个数确定可以使用数组,但是不确定的话,可以用集合,因为集合是可变长度的. 2.集合和数组的区别 数组是固定长度的,集 ...

  7. IOS开发环境

    当我们需要帮一些人学习IOS的时候,可以翻阅下这篇文章,我有个同学对IOS开发不太了解,用语言描述该怎么做的时候显得不够具体,或者全部需要我帮忙操作,又会占用我们的时间,如果每个人都这么要求的话,那么 ...

  8. Fiddler自动响应AutoResponder正则匹配

    AutoResponder-Add-Rule Editor 两个文本框,先说第一个: Mathes: 前缀为“EXACT:”表示完全匹配(大小写敏感) 无前缀表示基本搜索,表示搜索到字符串就匹配 前缀 ...

  9. python -- 安装 django

    django-admin startproject 创建的文件名python3/python manage.py startapp 子项目名称python3/python manage.py runs ...

  10. 解读typescript中 super关键字的用法

    解读typescript中 super关键字的用法 传统的js,使用prototype实现父.子类继承.如果父.子类有同名的方法,子类去调用父类的同名方法需要用 “父类.prototype.metho ...