springboot中多数据源的配置

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangxing52077/article/details/81236943

1.场景还原

   在实际项目中,一个工程配置多个数据源很常见,工程可能会根据业务或者模块访问不同的数据库或表;今天笔者就springboot中配置多数据源作个详细的讲解

2.实现方案

注意:一个应用工程中有且只有一个启动类,其依赖的模块不能是带有启动类的模块

①application.yml配置

spring:
  datasource:
    druid:
      master:  #数据源1
        url: jdbc:mysql://xxxx1:3306/online_test?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
        username: root
        password: root
      slave:  #数据源2
        url: jdbc:mysql://xxxxx2:3306/online_test?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
        username: root
        password: root
      driverClassName: com.mysql.jdbc.Driver
      #最大活跃数
      maxActive: 20
      #初始化数量
      initialSize: 1
      #最大连接等待超时时间
      maxWait: 60000
      #打开PSCache,并且指定每个连接PSCache的大小
      poolPreparedStatements: true
      maxPoolPreparedStatementPerConnectionSize: 20
      #通过connectionProperties属性来打开mergeSql功能;慢SQL记录
      #connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
      minIdle: 1
      timeBetweenEvictionRunsMillis: 60000
      minEvictableIdleTimeMillis: 300000
      validationQuery: select 1 from dual
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      #配置监控统计拦截的filters,去掉后监控界面sql将无法统计,'wall'用于防火墙
      filters: stat, wall, log4j

②pom依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-jdbc</artifactId>
   <version>5.0.7.RELEASE</version>
</dependency>

③自定义多数据源注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    String name() default "";
}

④多数据源切面处理类,实现数据库的选择

@Aspect
@Component
@Slf4j
public class DataSourceAspect implements Ordered {
    
    @Pointcut("@annotation(com.yivi.yivisender.dispatchorder.conf.datasources.annotation.DataSource)")
    public void dataSourcePointCut() {

    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();

        DataSource ds = method.getAnnotation(DataSource.class);
        if(ds == null){
            DynamicDataSource.setDataSource(DataSourceNames.MASTER);
            log.debug("set datasource is " + DataSourceNames.MASTER);
        }else {
            DynamicDataSource.setDataSource(ds.name());
            log.debug("set datasource is " + ds.name());
        }

        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            log.debug("clean datasource");
        }
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
public interface DataSourceNames {
    String MASTER = "master";

    String SLAVE = "slave";

}

⑤DynamicDataSource的申明,其作为工程全局的datasource使用

public class DynamicDataSource extends AbstractRoutingDataSource {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }

    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    public static String getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }

}

⑥动态数据源的配置

@Configuration
public class DynamicDataSourceConfig {

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

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

    @Bean
    @Primary
    public DynamicDataSource dataSource(DataSource masterDataSource, DataSource slaveDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceNames.MASTER, masterDataSource);
        targetDataSources.put(DataSourceNames.SLAVE, slaveDataSource);
        return new DynamicDataSource(masterDataSource, targetDataSources);
    }
}

⑦启动类的配置

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
@Import({DynamicDataSourceConfig.class})
@ComponentScan("com.yivi")
@MapperScan({"com.yivi.yivisender.dispatchorder.dao","com.yivi.yivisender.dispatchdata.dao","com.yivi.yivisender.dispatchcalengine.dao"})
public class DispatchorderApplication extends SpringBootServletInitializer {

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

   @Override
   protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
      return application.sources(DispatchorderApplication.class);
   }
}

3.测试效果

①多数据源测试类

@Service
public class DynasticServiceTest {
   @Autowired
   private YiViUserAccountMapper yiViUserAccountMapper;

    @DataSource(name = DataSourceNames.MASTER)
    public int addToMaster(String account ,String userId){
        return  yiViUserAccountMapper.increaseAccount(account,userId);

    }

    @DataSource(name = DataSourceNames.SLAVE)
    public int addToSlave(String account ,String userId){
        return  yiViUserAccountMapper.increaseAccount(account,userId);

    }
}

②测试主库插入

③测试从库插入

好了,我是张星,欢迎加入博主技术交流群,群号:526601468

猜你喜欢

转载自blog.csdn.net/zhangxing52077/article/details/81236943