SpringBoot 動態資料來源 用註解切換
阿新 • • 發佈:2018-12-18
使用版本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"); //key 值對應enum裡的名稱 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資料庫
}
}
以上就是了