SpringBoot 动态数据源 用注解切换

使用版本SpringBoot 1.5.9

动态切换数据源,mysql ,oracle 在项目中动态切换,或者 两个mysql进行切换

引入依赖


	com.alibaba
	druid-spring-boot-starter
	1.1.6


	org.mybatis.spring.boot
	mybatis-spring-boot-starter



	org.springframework.boot
	spring-boot-starter-aop

 

配置代码

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

以上就是了

 

你可能感兴趣的:(java)