阅读 688

动态切换数据源 spring-boot

AbstractRoutingDataSource

该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上。

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {

    private Map<Object, Object> targetDataSources;
    private Object defaultTargetDataSource;
    
     /* */
    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
        this.targetDataSources = targetDataSources;
    }

     /* */
    public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
        this.defaultTargetDataSource = defaultTargetDataSource;
    }

    /* */
    protected abstract Object determineCurrentLookupKey();

}
复制代码

具体实现

1、自定义 DynamicDataSource 类继承自AbstractRoutingDataSource

public class DynamicDataSource  extends AbstractRoutingDataSource{

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceHolder.getDataSource();
    }
}
复制代码

2、定义 DataSourceHolder 类。

ThreadLocal :为每个线程创建独立的局部变量副本,线程之间的ThradLocal互不影响(不同线程使用的不同的数据库,互不影响,线程安全)。

public class DataSourceHolder {

    private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

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

    public static void setDataSource(String dataSourceName) {
        threadLocal.set(dataSourceName);
    }


    public static void removeDataSource() {
        threadLocal.remove();
    }
}
复制代码

3、加载多数据源

@Configuration
public class DynamicDataConfig {


    @Bean(name = "default") // 初始化bean
    @ConfigurationProperties(prefix = "spring.datasource") //加载默认数据源
    public DataSource createDefaultTargetDataSource() {
        return DataSourceBuilder.create().build();
    }


    @Bean    
    @Primary // 指定使用 DynamicDataSource 来作为系统 dataSource 数据源
    public DynamicDataSource createDataSource(@Qualifier("default") DataSource defaultDataSource) {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
        dynamicDataSource.setTargetDataSources(getTargetDataSources());
        return dynamicDataSource;
    }

    /* 初始化 targetDataSources */
    public Map<Object, Object> getTargetDataSources() {
        Map<Object, Object> targetDataSources = new HashMap();
        targetDataSources.put("test_2",DataSourceBuilder.create()
                .url("jdbc:mysql://localhost:3306/test_2")
                .username("root")
                .password("yangyang")
                .driverClassName("com.mysql.jdbc.Driver")
                .build());
        return targetDataSources;
    }
}
复制代码

4、切换数据源 根据 targetDataSources 的 key 来实现切换数据源(切面调用,实现切换)

DataSourceHolder.setDataSource("test_2");
复制代码