zoukankan      html  css  js  c++  java
  • springboot多数据源

    springboot多数据源

    pom文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
       <modelVersion>4.0.0</modelVersion>
       <parent>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-parent</artifactId>
           <version>2.3.5.RELEASE</version>
           <relativePath/> <!-- lookup parent from repository -->
       </parent>
       <groupId>com.dtg</groupId>
       <artifactId>muldatasource</artifactId>
       <version>0.0.1-SNAPSHOT</version>
       <name>muldatasource</name>
       <description>Demo project for Spring Boot</description>

       <properties>
           <java.version>1.8</java.version>
       </properties>

       <dependencies>
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-data-jpa</artifactId>
           </dependency>
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-jdbc</artifactId>
           </dependency>
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-web</artifactId>
           </dependency>

           <dependency>
               <groupId>mysql</groupId>
               <artifactId>mysql-connector-java</artifactId>
               <version>5.1.25</version>
           </dependency>


           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-test</artifactId>
               <scope>test</scope>
               <exclusions>
                   <exclusion>
                       <groupId>org.junit.vintage</groupId>
                       <artifactId>junit-vintage-engine</artifactId>
                   </exclusion>
               </exclusions>
           </dependency>
       </dependencies>

       <build>
           <plugins>
               <plugin>
                   <groupId>org.springframework.boot</groupId>
                   <artifactId>spring-boot-maven-plugin</artifactId>
               </plugin>
           </plugins>
       </build>

    </project>

     

    application.yml配置文件

    增加读和写两个数据源

    spring:
    datasource:
      write:
      username: root
      password: root
      driver-class-name: com.mysql.jdbc.Driver
      jdbc-url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
      read:
      username: root
      password: root
      driver-class-name: com.mysql.jdbc.Driver
      jdbc-url: jdbc:mysql://127.0.0.1:3308/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

    ##

     

     

     

     

    定义数据源类型

    package com.dtg.muldatasource.constants;

    public enum DataSourceType {
       WRITE,
       READ
    }

    定义数据源holder

    holder维护了每个线程所需要的数据源类型,并对外暴露了设置数据源变量的方法。

    package com.dtg.muldatasource.config;

    public class DynamicDataSourceContextHolder {

       /**
        * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
        * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
        */
       private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

       /**
        * 设置数据源变量
        * @param dataSourceType
        */
       public static void setDataSourceType(String dataSourceType){
           System.out.println("切换到"+dataSourceType+"数据源");
           CONTEXT_HOLDER.set(dataSourceType);
      }

       /**
        * 获取数据源变量
        * @return
        */
       public static String getDataSourceType(){
           return CONTEXT_HOLDER.get();
      }

       /**
        * 清空数据源变量
        */
       public static void clearDataSourceType(){
           CONTEXT_HOLDER.remove();
      }
    }

    动态数据源类

    通常用 springboot 时都是使用它的默认配置,只需要在配置文件中定义好连接属性就行了,但是现在我们需要自己来配置了,spring 是支持多数据源的,多个 datasource 放在一个 HashMapTargetDataSource中,通过dertermineCurrentLookupKey获取 key 来觉定要使用哪个数据源。因此我们的目标就很明确了,建立多个 datasource 放到 TargetDataSource 中,同时重写 dertermineCurrentLookupKey 方法来决定使用哪个 key。

    这里的dertermineCurrentLookupKey 是查询DynamicDataSourceContextHolder中的数据源类型。

    package com.dtg.muldatasource.config;

    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

    import javax.sql.DataSource;
    import java.util.Map;

    public class DynamicDataSource extends AbstractRoutingDataSource {

       /**
        *
        * @param defaultTargetDataSource 默认的数据源
        * @param targetDataSources 支持的所有数据源
        */
       public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
           super.setDefaultTargetDataSource(defaultTargetDataSource);
           super.setTargetDataSources(targetDataSources);
           // afterPropertiesSet()方法调用时用来将targetDataSources的属性写入resolvedDataSources中的
           super.afterPropertiesSet();
      }

       /**
        * 重写该方法,根据Key获取数据源的信息
        *
        * @return
        */
       @Override
       protected Object determineCurrentLookupKey() {
           return DynamicDataSourceContextHolder.getDataSourceType();
      }
    }

     

    数据源配置类DataSourceConfig

    package com.dtg.muldatasource.config;

    import com.dtg.muldatasource.constants.DataSourceType;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;

    import javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;

    @Configuration
    public class DataSourceConfig {
       @Bean
       @ConfigurationProperties("spring.datasource.write")
       public DataSource writeDataSource() {
           return DataSourceBuilder.create().build();
      }

       @Bean
       @ConfigurationProperties("spring.datasource.read")
       public DataSource readDataSource() {
           return DataSourceBuilder.create().build();
      }

       @Bean(name = "dynamicDataSource")
       @Primary
       public DynamicDataSource dataSource(DataSource writeDataSource, DataSource readDataSource) {
           Map<Object, Object> targetDataSources = new HashMap<>();
           targetDataSources.put(DataSourceType.WRITE.name(), writeDataSource);
           targetDataSources.put(DataSourceType.READ.name(), readDataSource);
           return new DynamicDataSource(writeDataSource, targetDataSources);
      }

    }

    数据源注解

    package com.dtg.muldatasource.config;

    import com.dtg.muldatasource.constants.DataSourceType;

    import java.lang.annotation.*;

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface MyDataSource {
       /**
        * 切换数据源名称
        */
       DataSourceType value() default DataSourceType.WRITE;
    }

    数据源切面

    package com.dtg.muldatasource.aspect;

    import com.dtg.muldatasource.config.DynamicDataSourceContextHolder;
    import com.dtg.muldatasource.config.MyDataSource;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;

    import java.lang.reflect.Method;

    @Aspect
    @Order(1)
    @Component
    public class DataSourceAspect {

       @Pointcut("@annotation(com.dtg.muldatasource.config.MyDataSource)")
       public void dsPointCut() { }


       //@Before:在切入点方法执行之前执行该方法。
       @Before("dsPointCut()")
       public void  before(JoinPoint joinPoint){
           System.out.println("dsPointCut @before....");
      }

       // @AfterReturning:在切入点方法执行并有返回值才执行该方法。
       @AfterReturning("dsPointCut()")
       public void  AfterReturning(JoinPoint joinPoint){
           System.out.println("dsPointCut @AfterReturning....");
      }

       // @After:在执行切入点方法之后执行该方法。
       @After("dsPointCut()")
       public void  After(JoinPoint joinPoint){
           System.out.println("dsPointCut @After....");
      }

       @Around("dsPointCut()")
       public Object around(ProceedingJoinPoint point) throws Throwable {
           MethodSignature signature = (MethodSignature) point.getSignature();
           Method method = signature.getMethod();
           MyDataSource dataSource = method.getAnnotation(MyDataSource.class); //方法上获取 数据源的注解
           if (dataSource != null) {
               DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name()); //获取注解上的value
          }

           System.out.println("dsPointCut @Around start....");

           Object rs;
           try {
               rs =   point.proceed();
               return rs;
          } finally {
               // 销毁数据源 在执行方法之后
               DynamicDataSourceContextHolder.clearDataSourceType();
          }


      }
    }

     

    测试类:

     

    package com.dtg.muldatasource.controller;

    import com.dtg.muldatasource.config.MyDataSource;
    import com.dtg.muldatasource.constants.DataSourceType;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;

    import java.util.List;
    import java.util.Map;


    @RestController
    public class EmpController {

       @Autowired
       JdbcTemplate jdbcTemplate;

       @GetMapping("/write")
       @MyDataSource(value = DataSourceType.WRITE)
       public List<Map<String, Object>> local(){
           List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from customer");
           return maps;
      }
       @GetMapping("/read")
       @MyDataSource(value = DataSourceType.READ)
       public List<Map<String, Object>> remote(){
           List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from customer");
           return maps;
      }

    }

    启动类:

    package com.dtg.muldatasource;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
    public class MuldatasourceApplication {

       public static void main(String[] args) {
           SpringApplication.run(MuldatasourceApplication.class, args);
      }

    }

     

  • 相关阅读:
    [kuangbin带你飞]专题十二 基础DP1 E
    hdu 1203 I NEED A OFFER! (01背包)
    hdu 2602 Bone Collector (01背包)
    hdu 4513 吉哥系列故事——完美队形II (manacher)
    hdu 2203 亲和串 (KMP)
    hdu 1686 Oulipo (KMP)
    hdu 1251 统计难题 (字典树)
    hdu 2846 Repository (字典树)
    hdu 1711 Number Sequence (KMP)
    poj 3461 Oulipo(KMP)
  • 原文地址:https://www.cnblogs.com/datangguott/p/13950875.html
Copyright © 2011-2022 走看看