暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

mysql--------多数据源的实现方式

Lord Lean Notes 2020-02-08
547

当我们的业务越来越复杂时,可能会遇到多个数据源的情况,而我们的业务又达不到使用分库分表的插件的数据量和请求量时,这时我们可以采用数据源切换的方式来实现我们所需的业务。

我们可以采用接口或者枚举的方式来先创建好可以切换的数据源,请看代码如下:
    /* 这两个类来对应数据源,而且如果添加数据源也是特别方便的,方便后期
    数据源的扩展 */
    public interface DataSources {
    String MASTER_DB = "masterDB";


    String SLAVE_DB = "slaveDB";
    }
    @Configuration
    public class DataSourceConfig {
    //destroy-method="close"的作用是当数据库连接不使用的时候,就把该连接重新放到数据池中,方便下次使用调用.
    @Bean(destroyMethod = "close", name = DataSources.MASTER_DB)
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource(){
    return DataSourceBuilder.create().type(DruidDataSource.class).build();
    }


    @Bean(destroyMethod = "close", name = DataSources.SLAVE_DB)
    @ConfigurationProperties(prefix = "spring.datasource-slave")
    public DataSource dataSourceSlave(){
    return DataSourceBuilder.create().type(DruidDataSource.class).build();
    }
    }
    复制
    当我们配置好数据源之后,还需要配置mybatis的配置,来达到当我们切换数据源时对应的mybatis中的也可以切换,代码如下:
      @Configuration
      @MapperScan(basePackages = {"com.example.multilpeDataSource.dao"})
      public class MybatisConfig {


      @Autowired
      @Qualifier(DataSources.MASTER_DB)
      private DataSource masterDB;


      @Autowired
      @Qualifier(DataSources.SLAVE_DB)
      private DataSource slaveDB;


      @Bean(name = "dynamicDataSource")
      public DataSource dynamicDataSource(){
      DynamicDataSource dynamicDataSource = new DynamicDataSource();
      //设置默认数据源
      dynamicDataSource.setDefaultTargetDataSource(masterDB);


      //map用来存储数据源
      Map<Object , Object> dsMap = new HashMap<>();
      dsMap.put(DataSources.MASTER_DB, masterDB);
      dsMap.put(DataSources.SLAVE_DB, slaveDB);
      dynamicDataSource.setTargetDataSources(dsMap);


      return dynamicDataSource;
      }


      @Bean
      @ConfigurationProperties(prefix = "mybatis")
      public SqlSessionFactoryBean sqlSessionFactoryBean(){
      SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
      //配置数据源,这里是关键配置,如果没有将dynamicDataSource作为数据源则不能实现切换
      sqlSessionFactoryBean.setDataSource(dynamicDataSource());
      return sqlSessionFactoryBean;
      }


      }
      复制
      在完成mybatis的配置之后,我们可以看到我们是拿DynamicDataSource对象来存储可以切换的数据源的,并且我们采用重新设置SqlSessionFactoryBean中的数据源。
      下面就是切换数据源的核心部分了,我们这部分采用AOP+注解的方式,下面我们来看下这部分代码。
        /* 注解部分 */
        @Retention(RetentionPolicy.RUNTIME)
        @Target({
        ElementType.METHOD
        })
        public @interface RoutingDataSource {


        String value() default DataSources.MASTER_DB;
        }
        /* AOP部分 */
        @Aspect
        @Component
        public class DynamicDataSourceAspect {


        /**
        * 前置设置dataSource
        * @param joinPoint
        */
        @Before("@annotation(com.example.multilpeDataSource.config.RoutingDataSource)")
        public void beforeSwitchDS(JoinPoint joinPoint){
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
                /* 默认的数据源我们是从DataSourceContextHolder类中获取 */
        String dataSource = DataSourceContextHolder.DEFAULT_DATASOURCE;
                /* 然后判断我们的注解是否在我们设为切点的方法上 */
        if (method.isAnnotationPresent(RoutingDataSource.class)){
        RoutingDataSource routingDataSource = method.getDeclaredAnnotation(RoutingDataSource.class);
        dataSource = routingDataSource.value();
        }
        DataSourceContextHolder.setDB(dataSource);
        }


        /**
        * 后置清空缓存
        * @param joinPoint
        */
        @After("@annotation(com.example.multilpeDataSource.config.RoutingDataSource)")
        public void afterSwitchDS(JoinPoint joinPoint){
        DataSourceContextHolder.clearDB();
        }


        }
        复制
        上面的这段代码就是我们切换数据源的核心部分,我们可以看到,前置方法是当切点的方法上没有我们编写的注解时,就是默认的数据源,有的话,就是根据注解中的内容来设置数据源。后置方法是清空数据源。我们现在有了数据源的配置,有了存储所有数据源的配置,并且有了切换数据源的具体过程,那我们拿什么存储当前的数据源呢?答案是ThreadLocal,那我们为何使用ThreadLocal
        ThreadLocal是线程本地变量,它可以将一个变量的范围限制在同一个线程的使用范围内。并且在获取时可以直接通过get方法来获取。使用ThreadLocal可以极大的解决掉传参所带来的时间消耗,其是以消耗内存为代价的。
        现在我们就对多数据源的切换的方案有了一个认识,相信可以给大家带来一个好的思路。
        文章转载自Lord Lean Notes,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

        评论