SpringBoot多数据源动态切换

        本文环境是SpringBoot + Spring + Mybatis Plus

      思路 :

              1.配置多数据源

              2.使用注解来标记目标数据源

              3.使用AOP来动态切换数据源

       1.yml:

application.yml

#app
server:
    port: 8085
#spring
spring:
  profiles:
    active: dev
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    channel:
      name: bole_channel
      # druid相关配置
      # 监控统计拦截的filters
      filters: stat
      # -log4j
      # -wall
      # 配置初始化大小/最小/最大
      initial-size: 1
      min-idle: 1
      max-active: 20
      # 获取连接等待超时时间
      max-wait: 60000
      # 间隔多久进行一次检测,检测需要关闭的空闲连接
      time-between-eviction-runs-millis: 60000
      # 一个连接在池中最小生存的时间
      min-evictable-idle-time-millis: 300000
      validation-query: SELECT 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      # 打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为false
      pool-prepared-statements: false
      max-pool-prepared-statement-per-connection-size: 20
      driver-class-name: com.mysql.jdbc.Driver
    qlm:
      name: bole_qlm
      # druid相关配置
      # 监控统计拦截的filters
      filters: stat
      # -log4j
      # -wall
      # 配置初始化大小/最小/最大
      initial-size: 1
      min-idle: 1
      max-active: 20
      # 获取连接等待超时时间
      max-wait: 60000
      # 间隔多久进行一次检测,检测需要关闭的空闲连接
      time-between-eviction-runs-millis: 60000
      # 一个连接在池中最小生存的时间
      min-evictable-idle-time-millis: 300000
      validation-query: SELECT 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      # 打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为false
      pool-prepared-statements: false
      max-pool-prepared-statement-per-connection-size: 20
      driver-class-name: com.mysql.jdbc.Driver


#mybatis
mybatis-plus:
  # 如果是放在src/main/java目录下 classpath:/com/yourpackage/*/dao/*Mapper.xml
  # 如果是放在resource目录 classpath:/dao/*Mapper.xml
  mapper-locations: classpath*:/mapper/*Mapper.xml
  #实体扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: com.agent_web.api.entity
  typeEnumsPackage: com.agent_web.api.enums
  global-config:
    db-config:
    #主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
      id-type: AUTO
    # 字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
      field-strategy: not_empty
    # 驼峰下划线转换
      column-underline: true
    # mp2.3+ 全局表前缀 mp_
    # table-prefix: mp_
    # 刷新mapper 调试神器
    # refresh-dao: true
    # 数据库大写下划线转换
    # capital-mode: true
    # Sequence序列接口实现类配置
    # key-generator: com.baomidou.mybatisplus.incrementer.OracleKeyGenerator
    #逻辑删除配置(下面3个配置)
      logic-delete-value: 1
      logic-not-delete-value: 0
    # sql-injector: com.baomidou.mybatisplus.mapper.LogicSqlInjector
      db-type: mysql
    refresh: true

    # sql-injector: com.baomidou.mybatisplus.core.injector.ISqlInjector
    # 自定义填充策略接口实现
    # meta-object-handler: com.baomidou.springboot.MyMetaObjectHandler
  configuration:
    # 配置返回数据库(column下划线命名&&返回java实体是驼峰命名),自动匹配无需as(没开启这个,SQL需要写as: select user_id as userId)
    map-underscore-to-camel-case: true
    cache-enabled: false
#  type-enums-package: com.shengya.service.bean.enums

application-dev.xml

spring:
# 数据源
  datasource:
    channel:
      url: jdbc:mysql://localhost:3306/channel?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull
      username: admin    
      password: 111111
    qlm:
      url: jdbc:mysql://localhost:3306/qlm?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull
      username: admin
      password: 111111


      Config:

        继承Spring的AbstractRoutingDataSource类,该类相当于一个DataSource路由,可以根据key值自动切换对应数据源

package com.agent_web.api.config;

import com.agent_web.api.utils.DataSourceHolder;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * @author wise
 * @version 2.0.0
 * @createdate 2018-07-23 15:42.
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

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

      多数据源初始化:

package com.agent_web.api.config;

import com.agent_web.api.enums.CommonEnum;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

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

/** 多数据配置(初始化)
 * @author wise
 * @createdate 2018-07-23 15:41.
 */
@Configuration
public class MultipleDataSourceConfig {

    @Bean(name = "dataSourceChannel")
    @ConfigurationProperties(prefix = "spring.datasource.channel")
    public DataSource channelDataSource(){
        return new DruidDataSource();
    }

    @Bean(name = "dataSourceQlm")
    @ConfigurationProperties(prefix = "spring.datasource.qlm")
    public DataSource qlmDataSource(){
        return new DruidDataSource();
    }


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

        //初始化数据源
        HashMap<Object, Object> dataSourceMap = new HashMap();
        dataSourceMap.put(CommonEnum.DataSourceType.CHANNEL.name(),channelDataSource());
        dataSourceMap.put(CommonEnum.DataSourceType.QLM.name(),qlmDataSource());
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        return dynamicDataSource;
    }

    /**
     * 配置@Transactional注解事务
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}

      2.注解:@DataSource

package com.agent_web.api.annotation;

import com.agent_web.api.enums.CommonEnum;

import java.lang.annotation.*;

/**
 * @author wise
 * @createdate 2018-08-23 11:29.
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {

    CommonEnum.DataSourceType value() default CommonEnum.DataSourceType.CHANNEL;

}

CommonEnum:

public enum DataSourceType{
        CHANNEL,QLM
}

      3.使用AOP来实现数据源动态切换

package com.agent_web.api.aop;

import com.agent_web.api.annotation.DataSource;
import com.agent_web.api.enums.CommonEnum;
import com.agent_web.api.utils.DataSourceHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author wise
 * @createdate 2018-07-23 17:40.
 */
@Component
@Aspect
public class DataSourceAspect {

    /**  设定切面
     * @author  wise
     * @date    2018/7/23 0027  17:42
     * @param
     * @return  void
     */
    @Pointcut("@annotation(com.agent_web.api.annotation.DataSource)")
    private void pointcut() {

    }

    /**  在执行方法体之前切换数据源
     * @author  wise
     * @date    2018/7/23 0027  17:45
     * @param point
     * @return  void
     */
    @Before("pointcut()&&@annotation(com.agent_web.api.annotation.DataSource)")
    public void before (JoinPoint point) {
        try {
            //获取默认数据源
            CommonEnum.DataSourceType dataSourceType = CommonEnum.DataSourceType.CHANNEL;
            String methodName = point.getSignature().getName();
            //获取参数类型
            Class[] parameterTypes = ((MethodSignature) point.getSignature()).getParameterTypes();
            Method method = point.getTarget().getClass().getMethod(methodName, parameterTypes);
            //获取方法上的注解
            DataSource methodAnnotation = method.getAnnotation(DataSource.class);
            if (methodAnnotation != null && methodAnnotation.value() != null) {
                //设置目标数据源
                dataSourceType = methodAnnotation.value();
            }
            //切换数据源
            DataSourceHolder.setDataSource(dataSourceType.name());
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    /**  清除数据源
     * @author  wise
     * @date    2018/7/23 0027  17:50
     * @param point
     * @return  void
     */
    @After("pointcut()&&@annotation(com.agent_web.api.annotation.DataSource)")
    public void after(JoinPoint point){
        DataSourceHolder.clearDataSource();
    }

}

DataSourceHolder:

     这里使用ThreadLocal来存储数据源,保证当前线程的数据源是隔离状态的

package com.agent_web.api.utils;

import lombok.extern.log4j.Log4j2;

/** 数据源切换类
 * @author wise
 * @createdate 2018-07-23 17:24.
 */
@Log4j2
public class DataSourceHolder {


    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    public static void setDataSource(String dbType){
        log.info("切换数据源: {}" ,dbType);
        contextHolder.set(dbType);
    }

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

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

      其它:

        因为我们要使用自定义的数据观配置,所以需要关掉SpringBoot的自动数据源配置

        exclude = DataSourceAutoConfiguration.class

package com.agent_web.api;

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

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

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

      总结:

        在SpringMVC使用过动态数据源切换的小伙伴应该发现,其实都是一样的,只不过是SpringBoot的配置方式发生了改变而已,以前我们在XML中配置多数据源,现在换到了yml中,以上所有代码都经过了测试,如有问题,请您私信我

版权声明:本文为博主原创文章,转载请注明出处(https://blog.csdn.net/F1004145107/article/details/82022683)

原创文章 42 获赞 51 访问量 1万+

猜你喜欢

转载自blog.csdn.net/F1004145107/article/details/82022683
今日推荐