SpringBoot 動態數據源 用註解切換

使用版本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數據庫
    }
}

以上就是了

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章