Spring Boot 动态数据源之多数据源自动切换(注解版)

使用版本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数据库
    }
}

以上就是了

猜你喜欢

转载自blog.csdn.net/xulinglin520/article/details/83542491