java切换数据源(多数据源)
现在要在一个服务里设置两个数据源:oracle和mysql
1.需要写配置文件:
@Controller主要是加载spring配置类
@EnableTransactionManagement事务用法,在访问数据库的service中加@Transactional
@MapperScan指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类
@Configuration
@EnableTransactionManagement(order = -200)
@MapperScan("com.csair.mpms.mapper*")
public class MyBatiesPlusConfiguration {
// 精确到 master 目录,以便跟其他数据源隔离
static final String MAPPER_LOCATION = "classpath:mapper/*.xml";
/*
* 分页插件,自动识别数据库类型
* 多租户,请参考官网【插件扩展】
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 开启 PageHelper 的支持
//paginationInterceptor.setLocalPage(true);
return paginationInterceptor;
}
@Bean(name = "masterTransactionManager")
public DataSourceTransactionManager masterTransactionManager() {
return new DataSourceTransactionManager(masterDataSource());
}
@Bean(name = "masterSqlSessionFactory")
@Primary
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource)
throws Exception {
final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
sessionFactory.setDataSource(multipleDataSource(masterDataSource(),db2()));
MybatisConfiguration configuration = new MybatisConfiguration();
//configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCacheEnabled(false);
sessionFactory.setConfiguration(configuration);
sessionFactory.setPlugins(new Interceptor[]{ //PerformanceInterceptor(),OptimisticLockerInterceptor()
paginationInterceptor() //添加分页功能
});
sessionFactory.setMapperLocations(new
PathMatchingResourcePatternResolver()
.getResources(MAPPER_LOCATION));
return sessionFactory.getObject();
}
@Bean(name = "masterDataSource", destroyMethod = "close", initMethod = "init")
@ConfigurationProperties(prefix = "spring.datasource.druid.db1" )
public DataSource masterDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "db2")
@ConfigurationProperties(prefix = "spring.datasource.druid.db2" )
public DataSource db2 () {
return DruidDataSourceBuilder.create().build();
}
/**
* 动态数据源配置
* @return
*/
@Bean
@Primary
public DataSource multipleDataSource (@Qualifier("masterDataSource") DataSource mpmsDataSource,
@Qualifier("db2") DataSource db2 ) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map< Object, Object > targetDataSources = new HashMap<>();
targetDataSources.put(DBTypeEnum.db1.getValue(), mpmsDataSource );
targetDataSources.put(DBTypeEnum.db2.getValue(), db2);
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(mpmsDataSource);
return dynamicDataSource;
}
}
数据源:
DataSourceSwitch文件:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DataSourceSwitch {
DBTypeEnum value() default DBTypeEnum.db1;
}
DataSourceSwitchAspect文件:
@Component
@Aspect
@Order(-100)
@Slf4j
public class DataSourceSwitchAspect {
@Pointcut("execution(* com.csair.mpms.service.*.*(..))")
private void db1Aspect() {
}
@Pointcut("execution(* com.csair.mpms.db2Service.*.*(..))")
private void db2Aspect() {
}
@Pointcut("@annotation(DataSourceSwitch)")
private void dataSourceSwitch() {
}
@Before("db1Aspect()")
public void db1(JoinPoint joinPoint) {
log.info("切换到db1 数据源...");
setDataSource(joinPoint, DBTypeEnum.db1);
}
@Before("db2Aspect()")
public void db2(JoinPoint joinPoint) {
log.info("切换到db2 数据源...");
setDataSource(joinPoint, DBTypeEnum.db2);
}
@Before("dataSourceSwitch()")
public void dataSourceSwitch(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
DataSourceSwitch dataSourceSwitch = methodSignature.getMethod().getAnnotation(DataSourceSwitch.class);
if (dataSourceSwitch.value() != null) {
DbContextHolder.setDbType(dataSourceSwitch.value());
log.info("切换到{} 数据源...", dataSourceSwitch.value().getValue());
}
}
/**
* 添加注解方式,如果有注解优先注解,没有则按传过来的数据源配置
*
* @param joinPoint
* @param dbTypeEnum
*/
private void setDataSource(JoinPoint joinPoint, DBTypeEnum dbTypeEnum) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
DataSourceSwitch dataSourceSwitch = methodSignature.getMethod().getAnnotation(DataSourceSwitch.class);
if (Objects.isNull(dataSourceSwitch) || Objects.isNull(dataSourceSwitch.value())) {
DbContextHolder.setDbType(dbTypeEnum);
}
else {
log.info("根据注解来切换数据源,注解值为:" + dataSourceSwitch.value());
switch (dataSourceSwitch.value().getValue()) {
case "db1":
DbContextHolder.setDbType(DBTypeEnum.db1);
break;
case "db2":
DbContextHolder.setDbType(DBTypeEnum.db2);
break;
default:
DbContextHolder.setDbType(dbTypeEnum);
}
}
}
}
DbContextHolder文件:
public class DbContextHolder {
private static final ThreadLocal contextHolder = new ThreadLocal<>();
/**
* 设置数据源
* @param dbTypeEnum
*/
public static void setDbType(DBTypeEnum dbTypeEnum) {
contextHolder.set(dbTypeEnum.getValue());
}
/**
* 取得当前数据源
* @return
*/
public static String getDbType() {
return (String) contextHolder.get();
}
/**
* 清除上下文数据
*/
public static void clearDbType() {
contextHolder.remove();
}
}
DBTypeEnum文件:
public enum DBTypeEnum {
db1("db1"), db2("db2");
private String value;
DBTypeEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
DynamicDataSource文件:
public class DynamicDataSource extends AbstractRoutingDataSource {
/**
* 取得当前使用哪个数据源
* @return
*/
@Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDbType();
}
}
配置文件:
datasource:
druid:
db1:
username:
password:
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:
initialSize: 5
minIdle: 5
maxActive: 50
max-wait: 3000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
db2:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: com.mysql.cj.jdbc.Driver # mysql驱动包
url: