Springcloud+Mybatis使⽤多数据源的四种⽅式Springcloud+Mybatis使⽤多数据源的四种⽅式sql语句实现的四种功能
前段时间在做会员中⼼和中间件系统开发时,多次碰到多数据源配置问题,主要⽤到分包⽅式、参数化切换、注解+AOP、动态添加 这四种⽅式。这⾥做⼀下总结,分享下使⽤⼼得以及踩过的坑。
分包⽅式
数据源配置⽂件
在yml中,配置两个数据源,id分别为master和s1。
spring:
datasource:
master:
jdbcUrl: jdbc:mysql://x:xxxx/db1?.........
username: xxx
password: xxx
driverClassName: sql.cj.jdbc.Driver
s1:
jdbcUrl: jdbc:mysql://x:xxxx/db2?........
username: xxx
password: xxx
driverClassName: sql.cj.jdbc.Driver
复制代码
数据源配置类
master数据源配置类
注意点:
需要⽤@Primary注解指定默认数据源,否则spring不知道哪个是主数据源;
@MapperScan(basePackages = "apper.master", sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {
//默认数据源
@Bean(name = "masterDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.master")
public HikariDataSource masterDataSource() {
ate().type(HikariDataSource.class).build();
}
@Bean(name = "masterSqlSessionFactory")
@Primary
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource datasource, PaginationInterceptor paginationInterceptor)            throws Exception {
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(datasource);
bean.setMapperLocations(
// 设置mybatis的xml所在位置
new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/master/**/**.xml"));
bean.setPlugins(new Interceptor[]{paginationInterceptor});
Object();
}
@Bean(name = "masterSqlSessionTemplate")
@Primary
public SqlSessionTemplate masterSqlSessionTemplate(
@Qualifier("masterSqlSessionFactory") SqlSessionFactory sessionfactory) {
return new SqlSessionTemplate(sessionfactory);
}
}
复制代码
s1数据源配置类
@MapperScan(basePackages = "apper.s1", sqlSessionFactoryRef = "s1SqlSessionFactory")
public class S1DataSourceConfig {
@Bean(name = "s1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.s1")
public HikariDataSource s1DataSource() {
ate().type(HikariDataSource.class).build();
}
@Bean(name = "s1SqlSessionFactory")
public SqlSessionFactory s1SqlSessionFactory(@Qualifier("s1DataSource") DataSource datasource
, PaginationInterceptor paginationInterceptor)
throws Exception {
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(datasource);
bean.setMapperLocations(
// 设置mybatis的xml所在位置
new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/s1/**/**.xml"));
bean.setPlugins(new Interceptor[]{paginationInterceptor});
Object();
}
@Bean(name = "s1SqlSessionTemplate")
public SqlSessionTemplate s1SqlSessionTemplate(
@Qualifier("s1SqlSessionFactory") SqlSessionFactory sessionfactory) {
return new SqlSessionTemplate(sessionfactory);
}
}
复制代码
使⽤
可以看出,mapper接⼝、xml⽂件,需要按照不同的数据源分包。在操作数据库时,根据需要在service类中注⼊dao层。
特点分析
优点
实现起来简单,只需要编写数据源配置⽂件和配置类,mapper接⼝和xml⽂件注意分包即可。
缺点
很明显,如果后⾯要增加或删除数据源,不仅要修改数据源配置⽂件,还需要修改配置类。
例如增加⼀个数据源,同时还需要新写⼀个该数据源的配置类,同时还要考虑新建mapper接⼝包、xml包等,没有实现 “热插拔” 效果。参数化切换⽅式
思想
参数化切换数据源,意思是,业务侧需要根据当前业务参数,动态的切换到不同的数据源。
这与分包思想不同。分包的前提是在编写代码的时候,就已经知道当前需要⽤哪个数据源,⽽参数化切换数据源需要根据业务参数决定⽤哪个数据源。
例如,请求参数userType值为1时,需要切换到数据源slave1;请求参数userType值为2时,需要切换到数据源slave2。
/**伪代码**/
int userType = Type();
if (userType == 1){
//切换到数据源slave1
//数据库操作
} else if(userType == 2){
//切换到数据源slave2
//数据库操作
}
复制代码
设计思路
数据源注册
数据源配置类创建datasource时,从yml配置⽂件中读取所有数据源配置,⾃动创建每个数据源,并注册⾄bean⼯⼚和AbstractRoutingDatasource(后⾯聊聊这个),同时返回默认的数据源master。
数据源切换
(1)通过线程池处理请求,每个请求独占⼀个线程,这样每个线程切换数据源时互不影响。
(2)根据业务参数获取应切换的数据源ID,根据ID从数据源缓存池获取数据源bean;
(3)⽣成当前线程数据源key;
(4)将key设置到threadLocal;
(5)将key和数据源bean放⼊数据源缓存池;
(6)在执⾏mapper⽅法前,spring会调⽤determineCurrentLookupKey⽅法获取key,然后根据key去数据源缓存池取出数据源,然后getConnection获取该数据源连接;
(7)使⽤该数据源执⾏数据库操作;
(8)释放当前线程数据源。
AbstractRoutingDataSource源码分析
spring为我们提供了AbstractRoutingDataSource抽象类,该类就是实现动态切换数据源的关键。
我们看下该类的类图,其实现了DataSource接⼝。
我们看下它的getConnection⽅法的逻辑,其⾸先调⽤determineTargetDataSource来获取数据源,再获取数据库连接。很容易猜想到就是这⾥来决定具体使⽤哪个数据源的。
进⼊到determineTargetDataSource⽅法,我们可以看到它先是调⽤determineCurrentLookupKey获取到⼀个lookupKey,然后根据这个key去resolvedDataSources⾥去相应的数据源。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。