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数据库
    }
}

以上就是了

 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值