Mybatis动静数据源切换

1. 结构设计

首先看一下这个性能的架构设计

  • 咱们默认有一个缺省的数据源 Deault DataSource ,他是从配置文件中获取的,在利用刚开始启动时就注入,而在某些状况下,咱们须要在一次操作中短时或长时间的对其它的数据库进行操作,这就是所谓的数据源切换。
  • 为了保障新增加的数据源不会对其它线程的操作有英影响,咱们应用ThreadLocal来存储以后应用的数据源的相干信-息,创立上下文 DataSourceContextHolder 类,来保留以后线程的数据源。
  • 在Mybatis读取配置创立 Session 时,会注入 DynamicDataSource ,而 DynamicDataSource 通过读取以后线程变量能够获取本人设置的数据源,如果没有设置会注入默认的数据源,这个数据源来自于配置文件,调用流程如下图

2. 实现

public class DataSourceContextHolder {    // 以后线程应用的数据源,为null示意默认数据源    private static final ThreadLocal<DataSource> contextHolder = new InheritableThreadLocal<DataSource>();    // 以后线程应用过的数据源,不便事务    private static final List<DataSource> dataSources = new ArrayList<>();    // 全局内部数据源缓存    private static final HashMap<String, DataSource> map = new HashMap<>();    // 设置以后线程的数据源    public static void setDataSource(DruidDataSource datasource) {        if (!map.containsKey(datasource.getUrl())) {            contextHolder.set(datasource);            map.put(datasource.getUrl(), datasource);        }        else {            contextHolder.set(map.get(datasource.getUrl()));        }        dataSources.add(contextHolder.get());    }    // 获取数据源    public static DataSource getDataSource() {        return contextHolder.get();    }    // 获取数据源    public static List<DataSource> getThreadDataSources() {        return dataSources;    }    public static void clearCache() {        map.clear();    }    public static void clearDataSource() {        contextHolder.remove();    }}
@Configurationpublic class DataSourceConfig {            @Bean(name = "defaultDataSource")    @ConfigurationProperties(prefix = "jdbc")    public DataSource defaultDataSource() {        return new DruidDataSource();    }    @Bean(name = "dynamicDataSource")    public DynamicDataSource dynamicDataSource() {        return new DynamicDataSource();    }}
/** * 动静数据源治理类 */public class DynamicDataSource extends AbstractDataSource {        // 注入默认数据源    @Resource(name = "defaultDataSource")    private DataSource defaultDs;    protected DataSource determineTargetDataSource() {        // 获取以后线程的数据源        DataSource dataSource = DataSourceContextHolder.getDataSource();        // 如果没有设置动静数据源,则返回默认数据源        if (dataSource == null) {            return defaultDs;        }        return dataSource;    }    @Override    public Connection getConnection() throws SQLException {        return determineTargetDataSource().getConnection();    }    @Override    public Connection getConnection(String username, String password) throws SQLException {        return determineTargetDataSource().getConnection(username, password);    }}
@Configurationpublic class MyBatisConfig {    @Resource(name = "dynamicDataSource")    private DynamicDataSource dynamicDataSource;    @Bean    public SqlSessionFactory sqlSessionFactory() throws Exception {        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();        sqlSessionFactoryBean.setObjectWrapperFactory(new MapWrapperFactory());        // 设置数据源为DynamicDataSource        sqlSessionFactoryBean.setDataSource(dynamicDataSource);        sqlSessionFactoryBean.setTypeAliasesPackage("me.ezerror.pojo");        return sqlSessionFactoryBean.getObject();    }    @Bean    public SqlSessionTemplate financialMasterSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {        return new SqlSessionTemplate(sqlSessionFactory);    }}

3.应用形式

// 新建数据源DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl(url);dataSource.setPassword(pwd);dataSource.setUsername(username);// 设置数据源DataSourceContextHolder.setDataSource(dataSource);// 数据库操作List<Moment> moments = recordService.findMoment();// 革除数据源,还原到默认数据源DataSourceContextHolder.clearDataSource();