使用版本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>
配置代碼
/**
* Created by XuLingLin on 2019/2/18
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
//切換數據源
@Override
protected Object determineCurrentLookupKey() {
return DatabaseContextHolder.getDatabaseType();
}
}
@Component
public class DatabaseContextHolder {
//創建 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 {
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 dataSource1 = 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");
//key 值對應enum裏的名稱
druidDataSourceMap.put(DatabaseType.mysql1,dataSource1);
druidDataSourceMap.put(DatabaseType.mysql2,dataSource2);
DynamicDataSource dataSource = new DynamicDataSource();
// 該方法是AbstractRoutingDataSource的方法
dataSource.setTargetDataSources(druidDataSourceMap);
// 默認使用的datasource
dataSource.setDefaultTargetDataSource(dataSource1);
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數據庫
}
}
以上就是了