关于java:Mybatis动态数据源切换

10次阅读

共计 3047 个字符,预计需要花费 8 分钟才能阅读完成。

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

}
@Configuration
public 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);
    }
}
@Configuration
public 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();
正文完
 0