使用版本SpringBoot 1.5.9
动态切换数据源,mysql ,oracle 在项目中动态切换,或者 两个mysql进行切换
引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
配置代码
@Component
public class DatabaseContext {
//创建 ThreadLocal 用余存储唯一的线程变量
private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>();
//添加
public static void setDatabaseType(DatabaseType type) {
contextHolder.set(type);
}
//获取
public static DatabaseType getDatabaseType() {
return contextHolder.get();
}
//删除
/*
*注意使用完成之后 需要删除线程变量
*ThreadLocal不会自动清理
*/
public static void clearDBKey() { contextHolder.remove(); }
}
//定义一个枚举对应配置文件里的名称
public enum DatabaseType {
mysql1,mysql2
}
//自定义注解
@Target({ ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TargetDataSource {
DatabaseType value();
}
//配置类
@Configuration
@MapperScan("xxxx")//包名
@EnableTransactionManagement
public class DataSourceConfig {
@Resource
private DataSourceProperties dataSourceProperties;
private static Logger logger = LoggerFactory.getLogger(DataSourceConfig.class);
@Autowired
private Environment env;
/**
* 构造多数据源连接池
*/
@Bean
@Primary
public DynamicDataSource dynamicDataSource() throws SQLException{
Map<Object,Object> druidDataSourceMap = new ConcurrentHashMap<>();
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql:///test1");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("xxxxx");
DruidDataSource dataSource2 = new DruidDataSource();
dataSource2.setUrl("jdbc:mysql:///test2");
dataSource2.setDriverClassName("com.mysql.jdbc.Driver");
dataSource2.setUsername("root");
dataSource2.setPassword("xxxxx");
druidDataSourceMap.put(DatabaseType.mysql1,dataSource);
druidDataSourceMap.put(DatabaseType.mysql2,dataSource2);
DynamicDataSource dataSource = new DynamicDataSource();
// 该方法是AbstractRoutingDataSource的方法
dataSource.setTargetDataSources(druidDataSourceMap);
//需要用 DatabaseType 类型获取
DruidDataSource druidDataSource = (DruidDataSource) druidDataSourceMap.get(DatabaseType.valueOf(defaultsKys));
logger.info("load defaults : " + defaultsKys);
// 默认使用的datasource
dataSource.setDefaultTargetDataSource(druidDataSource);
return dataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource) throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dynamicDataSource);
sessionFactoryBean.setTypeAliasesPackage(env.getProperty("mybatis.type-aliases-package"));
sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapper-locations")));
return sessionFactoryBean.getObject();
}
@Bean
public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {
return new DataSourceTransactionManager(dataSource);
}
}
AOP实现切换
@Aspect
@Order(-10)
@Component
public class DynamicDataSourceAspect {
private static Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
@Pointcut("@annotation(targetDataSource)")
public void pointCut(TargetDataSource targetDataSource) {}
/*
*
* @Before:在方法执行之前进行执行:
* @annotation(targetDataSource):
* 会拦截注解targetDataSource的方法,否则不拦截;
*/
@Before("pointCut(targetDataSource)")
public void doBefore(JoinPoint point,TargetDataSource targetDataSource){
//获取当前的指定的数据源;
DatabaseType value = targetDataSource.value();
//如果不在会使用默认的。
if (targetDataSource.value()==null){
//找到的话,那么设置到动态数据源上下文中。
DatabaseContext.setDatabaseType(targetDataSource.value());
}
}
/**
* 清理
*/
@After("pointCut(targetDataSource)")
public void after(TargetDataSource targetDataSource){
DatabaseContextHolder.clearDBKey();
}
}
测试
@RestController
@RequestMapping("/test")
public class TestController {
//在访问方法上加入注解即可
@TargetDataSource(DatabaseType.mysql1)
@GetMapping("/test1")
public String test1(){
//会调用 test1数据库
}
@TargetDataSource(DatabaseType.mysql2)
@GetMapping("/test2")
public String test2(){
//会调用 test2数据库
}
}
以上就是了