seamew的妙妙屋seamew的妙妙屋
首页
  • kafka监控
  • my-spring
  • Gitee
  • Github
首页
  • kafka监控
  • my-spring
  • Gitee
  • Github
  • BUG

    • BeanUtils报错
    • Thread的名字问题
  • JAVA

    • Threadlocal
    • 线程池源码分析
  • JS进阶

    • JS开发技巧
  • linux

    • centos防火墙
    • vagrant
    • 正则表达式
  • springboot进阶学习

    • @Configuration和@Bean注解
    • springboot接收参数详解
    • springboot配置多数据源
    • 事务导致多数据源切换失败
  • spring进阶学习

    • aop创建代理基本流程
    • 三级缓存解决循环依赖
  • 云原生

    • 自动化部署
  • 前端开发

    • vue-computed计算属性引发的BUG
  • 大数据

    • kafka事务
    • zookeeper
  • 算法

    • 动态规划

      • 动态规划基础理论
      • 抛骰子和为k的概率
    • 回溯算法

      • used数组是局部还是全局
      • 最优解快速返回
    • 图论

      • dfs简介
    • 多线程

      • 打印ABC
    • 贪心

      • 小于n的最大数字

1、创建配置类

@Configuration
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties("spring.datasource.master")
    public DataSource masterDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.slave01")
    @ConditionalOnProperty(prefix = "spring.datasource.slave01", name = "enabled", havingValue = "true")
    public DataSource slave01DataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DynamicDataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        //配置默认数据源
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource());
        //配置多数据源
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceType.MASTER.getSourceName(), masterDataSource());
        targetDataSources.put(DataSourceType.SLAVE01.getSourceName(), slave01DataSource());
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }
}

2、配置yaml文件

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    # 主库数据源
    master:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://192.168.100.60:3306/demo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
      username: root
      password: root
    # 从库数据源
    slave01:
      enabled: true
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://192.168.100.60:3306/demo01?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
      username: root
      password: root

3、配置数据源切换

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceType();
    }
}

4、使用线程类切换数据源

@Slf4j
public class DataSourceContextHolder {
    /**
     * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
     *  所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
     */
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    /**
     * 设置数据源变量
     * @param dataSourceType
     */
    public static void setDataSourceType(String dataSourceType){
        log.info("切换到{}数据源", dataSourceType);
        CONTEXT_HOLDER.set(dataSourceType);
    }

    /**
     * 获取数据源变量
     * @return
     */
    public static String getDataSourceType(){
        return CONTEXT_HOLDER.get();
    }

    /**
     * 清空数据源变量
     */
    public static void clearDataSourceType(){
        CONTEXT_HOLDER.remove();
    }
}

5、多数据源的使用

public List<User> findAll() {
    DataSourceContextHolder.setDataSourceType("slave01");
    List<User> users = userDao.findAll();
    DataSourceContextHolder.clearDataSourceType();
    return users;
}

6、DataSource源码

protected DataSource determineTargetDataSource() {
    Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
    // 根据determineCurrentLookupKey函数返回map的key
    Object lookupKey = determineCurrentLookupKey();
    DataSource dataSource = this.resolvedDataSources.get(lookupKey);
    // 如果找的到key对应的value则使用其他数据源,要不然使用默认的
    if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
        dataSource = this.resolvedDefaultDataSource;
    }
    if (dataSource == null) {
        throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
    }
    return dataSource;
}
上次更新: 2026/3/21 07:25
上一页
springboot接收参数详解
下一页
事务导致多数据源切换失败