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();