基于 AbstractRoutingDataSource扩展,加AOP动态切换数据源
demo 测试使用 两个 库 db0 db1
create database db0;
create database db1;
use db0;
drop table if exists t_user;
CREATE TABLE `t_user` (
`id` int(11) PRIMARY key auto_increment COMMENT '用户编号',
`user_name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '账号',
UNIQUE KEY `idx_user_name` (`user_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
insert into t_user(user_name) values('阿离');
insert into t_user(user_name) values('奏');
insert into t_user(user_name) values('阿花 ');
use db1;
drop table if exists t_order;
CREATE TABLE `t_order` (
`id` int(11) PRIMARY key auto_increment COMMENT '订单编号',
`user_id` int(16) DEFAULT NULL COMMENT '用户编号'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='订单表';
insert into t_order(user_id) values(123);
insert into t_order(user_id) values(45);
insert into t_order(user_id) values(789);
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--AOP-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 实现对数据库连接池的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--MySQL-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<!--MyBatis 及 插件依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.13</version>
</dependency>
</dependencies>
# db0
spring.datasource.druid.db0.url=jdbc:mysql://127.0.0.1:3306/db0?useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.datasource.druid.db0.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.db0.username=root
spring.datasource.druid.db0.password=123456
# db1
spring.datasource.druid.db1.url=jdbc:mysql://127.0.0.1:3306/db1?useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.datasource.druid.db1.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.db1.username=root
spring.datasource.druid.db1.password=123456
@EnableTransactionManagement
@Configuration
@MapperScan(basePackages ={
"com.zou.dao.db0.mapper","com.zou.dao.db1.mapper"})
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
return paginationInterceptor;
}
@Bean(name = Constant.DB0)
@ConfigurationProperties(prefix = "spring.datasource.druid.db0")
public DataSource db0() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = Constant.DB1)
@Primary
@ConfigurationProperties(prefix = "spring.datasource.druid.db1")
public DataSource db1() {
return DruidDataSourceBuilder.create().build();
}
/**
* 动态数据源配置
* @param db0
* @param db1
* @return javax.sql.DataSource
* @author wh
* @date 2020/7/21
*/
@Bean
public DataSource multipleDataSource(@Qualifier(Constant.DB0) DataSource db0,
@Qualifier(Constant.DB1) DataSource db1) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(Constant.DB0, db0);
targetDataSources.put(Constant.DB1, db1);
dynamicDataSource.setTargetDataSources(targetDataSources);
// 设置默认数据源
dynamicDataSource.setDefaultTargetDataSource(db0);
return dynamicDataSource;
}
/**
* 事务管理器
* @param
* @return DataSourceTransactionManager
* @author wh
* @date 2020/7/27
*/
@Bean
public DataSourceTransactionManager transactionManager () {
return new DataSourceTransactionManager( multipleDataSource(db0(), db1()) );
}
@Bean
@Primary
public MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean () throws Exception{
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
bean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
// 实体类别名
bean.setTypeAliasesPackage("com.zou.model");
MybatisConfiguration configuration = new MybatisConfiguration();
//开启下划线转驼峰
configuration.setMapUnderscoreToCamelCase(true);
configuration.setJdbcTypeForNull(JdbcType.NULL);
bean.setDataSource(multipleDataSource(db0(), db1()));
return bean;
}
}
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
final String lookupKey = DbContextHolder.getDbType();
DbContextHolder.clearDbType();
return lookupKey;
}
}
public class DbContextHolder {
private static final ThreadLocal<String> contextHolder = ThreadLocal.withInitial(String::new);
/**
* 设置数据源
* @param dbType
* @return void
* @author wh
* @date 2020/7/21
*/
public static void setDbType(String dbType) {
contextHolder.set(dbType);
}
/**
* 取得当前数据源
* @param
* @return java.lang.String
* @author wh
* @date 2020/7/21
*/
public static String getDbType() {
System.out.println("获取数据源为:" + contextHolder.get());
return contextHolder.get();
}
/**
* 清除上下文数据
*/
public static void clearDbType() {
contextHolder.remove();
}
}
@Component
@Order(value = -100)
@Aspect
@Slf4j
public class DataSourceSwitchAspect {
private static final String DB0= "execution(* com.zou.dao.db0..*.*(..))";
private static final String DB1 = "execution(* com.zou.dao.db1..*.*(..))";
@Pointcut(DB0)
private void db0Aspect() {
}
@Pointcut(DB1)
private void db1Aspect() {
}
@Before("db0Aspect()")
public void dsc() {
DbContextHolder.setDbType(Constant.DB0);
}
@Before("db1Aspect()")
public void admin() {
DbContextHolder.setDbType(Constant.DB1);
}
}
目前动态切换数据源已经配置成功了,我们仅需要在db0,db1开发自己业务即可动态切换,由于篇幅这里不给出其他类,感兴趣可以自己下载源码
运行测试类 TestService 中的 getOrderAndUser 方法即可
这里可以看到是查询了我们配置的两个库
后续将介绍配置多个 SqlSessionTemplate 来实现多数据源