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;
    }
複製代碼

測試沒有問題,能夠動態的根據註解切換數據源,在結合以前的主從數據庫配置就能夠進一步的實現讀寫分離。

相關文章
相關標籤/搜索