SpringBoot+mybatis多数据源切换讲解
1.背景:在工作中有多数据库源切换使用的场景,用别人写好的东西很方便,但是自己不知道原理用起来就是不放心
步骤一
引入所需的maven,版本选择自己适合的就好
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.3.0</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
自定义一个注解,用来实现在方法层面的数据库切换,一般来说为了代码的规范性,我们都会再写一个这种公共常量定义类
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Documented
public @interface TargetDataSource {
String value() default DataSourceEnum.MasterDataSource;//你要选择的数据名称,建议写上默认值,你也不想每个涉及到数据库方法时都得加个注解吧
}
@Getter
public class DataSourceEnum {
public static final String MasterDataSource = "first";
public static final String SecondDataSource = "second";
}
步骤二
设置一个全局静态变量来保存我们的数据源配置
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}
public static String getDataSourceType() {
return contextHolder.get();
}
public static void clearDataSourceType() {
contextHolder.remove();
}
}
步骤三
将具体的数据库信息从我们的配置文件中读取出来,如Nacos中或者本地的application.yml
通过@ConfigurationProperties,prefix中的信息就按照你的配置来,这里我们注入了两个数据库
@Configuration
public class DataSourceConfig {
@Bean(name = DataSourceEnum.MasterDataSource)
@ConfigurationProperties(prefix = "spring.datasource.first")
public DataSource firstDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = DataSourceEnum.SecondDataSource)
@ConfigurationProperties(prefix = "spring.datasource.second")
public DataSource secondDataSource() {
return DataSourceBuilder.create().build();
}
// 动态数据源
@Primary
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource(@Qualifier(DataSourceEnum.MasterDataSource) DataSource defaultDataSource,
@Qualifier(DataSourceEnum.SecondDataSource) DataSource secondaryDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceEnum.MasterDataSource, defaultDataSource);
targetDataSources.put(DataSourceEnum.SecondDataSource, secondaryDataSource);
AbstractRoutingDataSource dynamicDataSource = new AbstractRoutingDataSource() {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
};
dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
dynamicDataSource.setTargetDataSources(targetDataSources);
return dynamicDataSource;
}
}
步骤四
通过切面AOP技术,将我们定义的注解拦截下来,每当Sping检查到我们的注解时,去读取我们在前面全局变量保存的信息,去做数据源切换。
通过@Before,在方法执行前去切换,注意要有@After去把这一次数据库连接完后去删除掉你切换的数据源,不然会影响其他方法。
@Aspect
@Component
public class DataSourceAspect {
@Before("@annotation(targetDataSource)")
public void beforeSwitchDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource) {
String dataSourceName = targetDataSource.value();
DataSourceContextHolder.setDataSourceType(dataSourceName);
}
@After("@annotation(targetDataSource)")
public void afterSwitchDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource) {
DataSourceContextHolder.clearDataSourceType();
}
}
步骤五
将我们定义的dynamicDataSource
通过sqlSessionFactory注入mybatis,使其生效。Mybaits在SpringBoot启动时会去查找类型为DataSource
的Bean,这就是为什么那里要加一个@Primary。DataSource必须先Mybaits一步注入进去,不然就错过了。
@Configuration
@MapperScan(basePackages = "com.lordyi.mapper",sqlSessionFactoryRef = "sqlSessionFactory")
public class MybatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dynamicDataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactory=new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dynamicDataSource);
return sqlSessionFactory.getObject();
}
}
步骤六
把自己的数据库配置写好
spring:
datasource:
first:
jdbc-url: jdbc:mysql://****:3306/***?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8
username: **
password: **
driver-class-name: com.mysql.cj.jdbc.Driver
second:
jdbc-url: jdbc:mysql://****:3306/***?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8
username: **
password: **
driver-class-name: com.mysql.cj.jdbc.Driver
到这一步你就可以愉快的拿着@TargetDataSource(“youDataBase”)玩耍了,觉得对您有帮助的请点一个免费的赞。