SprinBoot 多数据源配置

Spring boot提供了AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源,这样咱们能够在执行查询以前,设置使用的数据源。实现可动态路由的数据源,在每次数据库查询操做前执行。它的抽象方法 determineCurrentLookupKey() 决定使用哪一个数据源,这里使用aop实现。mysql

一、数据准备,两个数据库,分别为 “springboot”、“springboot_1”spring

测试表booksql

CREATE TABLE `book` (
  `id` int(11) NOT NULL,
  `book_name` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `book_index` (`id`,`book_name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
复制代码

测试数据数据库

INSERT INTO springboot.book(id, book_name) VALUES (1, '测试,来自主库');
INSERT INTO springboot_1.book(id, book_name) VALUES (1, '测试,来自从库');
复制代码

二、pom.xmlspringboot

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>
复制代码

三、application.yml 配置多个数据源bash

spring:
  #数据库配置
  datasource:
    # type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver

    druid:
      master:
        jdbc-url: jdbc:mysql://192.0.0.210:3306/springboot?useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true
        username: root
        password: 123456

      slave:
        jdbc-url: jdbc:mysql://192.0.0.210:3306/springboot_1?useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true
        username: root
        password: 123456


      maxActive: 20
      initialSize: 1
      maxWait: 60000
      minIdle: 1
      timeBetweenEvictionRunsMillis: 60000
      minEvictableIdleTimeMillis: 300000
      validationQuery: select 'x'
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      poolPreparedStatements: true
      maxOpenPreparedStatements: 20
复制代码

四、自定义注解类app

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MoreDataSource {
    public static String master = "master";
    public static String slave = "slave";

    String name() default MoreDataSource.slave;
}

复制代码

五、新建DynamicDataSource类,扩展Spring的AbstractRoutingDataSource抽象类,重写 determineCurrentLookupKey() 方法ide

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        #在第6步建立
        String key = DataSourceHolder.getDataSourceKey();
        if (StringUtils.isBlank(key)) {
            return MoreDataSource.master;
        }
        return key;
    }
}

复制代码

六、新建DataSourceHolder类,一个拥有ThreadLocal变量的类,用来存取数据源名称spring-boot

public class DataSourceHolder {
    private static final ThreadLocal<String> dataSources = new ThreadLocal<>();

    public static void setDataSourceKey(String customType) {
        dataSources.set(customType);
    }

    public static String getDataSourceKey() {
        return (String) dataSources.get();
    }

    public static void clearDataSourceKey() {
        dataSources.remove();
    }
}

复制代码

七、新建多数据源配置类DataSourceConfig测试

@Configuration
public class DataSourceConfig {
    @Bean
    @Primary
    public DataSource dataSource() {
        DynamicDataSource resolver = new DynamicDataSource();
        Map<Object, Object> dataSources = Maps.newHashMap();
        dataSources.put(MoreDataSource.master, masterDataSource());
        dataSources.put(MoreDataSource.slave, slaveDataSource());
        resolver.setTargetDataSources(dataSources);
        return resolver;
    }

    @Bean
    @ConfigurationProperties(prefix="spring.datasource.druid.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix="spring.datasource.druid.slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }

}

复制代码

八、新建切面类DataSourceAspect

@Aspect
@Component
public class DataSourceAspect {
    @Pointcut("@annotation(com.test.annotation.MoreDataSource)")
    public void aspect() {
    }

    @Before("aspect()")
    public void doBefore(JoinPoint point) throws Throwable {
        final MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Method method = methodSignature.getMethod();
        MoreDataSource mzDataSource = method.getAnnotation(MoreDataSource.class);
        if (method.getDeclaringClass().isInterface()) {
            method = point.getTarget().getClass().getMethod(method.getName(), method.getParameterTypes());
        }
        mzDataSource = method.getAnnotation(MoreDataSource.class);
        if (null != mzDataSource) {
            DataSourceHolder.setDataSourceKey(mzDataSource.name());
        }

        System.out.println("数据源切换:" + DataSourceHolder.getDataSourceKey());
    }

    @After("aspect()")
    public void doAfter() {
        DataSourceHolder.clearDataSourceKey();
    }
}

复制代码

九、修改启动类,由于数据源是本身生成的,因此要去掉原先springboot启动时候自动装配的数据源配置

加上注解

@Import({DataSourceConfig.class})
复制代码

十、测试

controller

@RequestMapping(value="/list/{id}")
    @ResponseBody
    public Book list(@PathVariable(value = "id") Integer id){
        Book book = bookService.findById(id);
        return book;
    }

    @RequestMapping(value="/list2/{id}")
    @ResponseBody
    @MoreDataSource
    public Book list2(@PathVariable(value = "id") Integer id){
        Book book = bookService.findById(id);
        return book;
    }
复制代码

测试没有问题,能够动态的根据注解切换数据源,在结合以前的主从数据库配置就能够进一步的实现读写分离。

相关文章
相关标签/搜索