栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot多数据源(2):动态配置多数据源

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot多数据源(2):动态配置多数据源

SpringBoot多数据源配置

文章目录
  • SpringBoot多数据源配置
  • 1、动态配置数据源
    • 1.1、项目结构
    • 1.2、配置文件
    • 1.3、动态数据源配置
      • 1.3.1、获取动态数据源类
      • 1.3.2、动态选择数据源
      • 1.3.3、配置类
      • 1.3.4、如何使用
  • 2、通过AOP动态获取数据源
    • 2.1、项目结构
    • 2.2、自定义注解
    • 2.3、AOP切面
    • 2.4、如何使用
  • 3、客户可通过接口直接配置数据源
    • 3.1、代码


1、动态配置数据源

项目地址

https://github.com/zhengguofeng1998/DynamicDataSource/tree/master/SecondDemo

1.1、项目结构

1.2、配置文件
server:
  port: 1816
spring:
  datasource:
    primary:
      url: jdbc:mysql://localhost:3306/seata_account?useUnicode=true&characterEncoding=utf-8&useSSL=false
      username: root
      password: 123456
      driver-class-name: org.gjt.mm.mysql.Driver
    slave:
      url: jdbc:mysql://localhost:3306/seata_order?useUnicode=true&characterEncoding=utf-8&useSSL=false
      username: root
      password: 123456
      driver-class-name: org.gjt.mm.mysql.Driver
  application:
    name: dynamic-datasource

# mybatis-plus
mybatis-plus:
  type-aliases-package: com.zgf.springcloud.domain
  # 默认位置,可不配置
#  mapper-locations: classpath*:/mapper*.xml

1.3、动态数据源配置 1.3.1、获取动态数据源类
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getContextKey();
    }
}
  • 继承抽象类 AbstractRoutingDataSource ,需要实现方法 determineCurrentLookupKey,即路由策略。
  • 动态路由策略下一步实现,当前策略直接返回 primary数据源
1.3.2、动态选择数据源
public class DynamicDataSourceContextHolder {
    
    private static final ThreadLocal DATASOURCE_CONTEXT_KEY_HOLDER = new ThreadLocal<>();

    
    public static void setContextKey(String key) {
        DATASOURCE_CONTEXT_KEY_HOLDER.set(key);
    }

    
    public static String getContextKey() {
        String key = DATASOURCE_CONTEXT_KEY_HOLDER.get();
        return key == null ? DataSourceConstants.DS_KEY_PRIMARY : key;
    }

    
    public static void removeContextKey() {
        DATASOURCE_CONTEXT_KEY_HOLDER.remove();
    }
}
  • 利用ThreadLocal保存数据源,value未dataSource,线程隔离
  • DynamicDataSourceContextHolder默认获取DS_KEY_PRIMARY数据源
1.3.3、配置类
@Configuration
@MapperScan(basePackages = "com.zgf.springcloud.mapper")
public class DynamicDataSourceConfig {

    @Bean(DataSourceConstants.DS_KEY_PRIMARY)
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DruidDataSource primaryDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        return dataSource(druidDataSource);
    }

    @Bean(DataSourceConstants.DS_KEY_SLAVE)
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DruidDataSource slaveDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        return dataSource(druidDataSource);
    }

    public DruidDataSource dataSource(DruidDataSource druidDataSource) {
        druidDataSource.setInitialSize(0);
        druidDataSource.setMaxActive(180);
        druidDataSource.setMaxWait(60000);
        druidDataSource.setMinIdle(0);
        druidDataSource.setValidationQuery("Select 1 from DUAL");
        druidDataSource.setTestOnBorrow(false);
        druidDataSource.setTestOnReturn(false);
        druidDataSource.setTestWhileIdle(true);
        druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
        druidDataSource.setMinEvictableIdleTimeMillis(25200000);
        druidDataSource.setRemoveAbandoned(true);
        druidDataSource.setRemoveAbandonedTimeout(1800);
        druidDataSource.setLogAbandoned(true);
        return druidDataSource;
    }

    @Bean
    @Primary
    public DataSource dynamicDataSource() {
        Map dataSourceMap = new HashMap<>(2);
        dataSourceMap.put(DataSourceConstants.DS_KEY_PRIMARY, primaryDataSource());
        dataSourceMap.put(DataSourceConstants.DS_KEY_SLAVE, slaveDataSource());
        //设置动态数据源
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        dynamicDataSource.setDefaultTargetDataSource(primaryDataSource());
        return dynamicDataSource;
    }
}
  • @MapperScan扫描多数据源共同的mapper文件,统一配置,不需要单独扫描
  • @ConfigurationProperties读取配置文件的数据
  • 将数据当如到map中存入DynamicDataSource
1.3.4、如何使用
    @Override
    public OrderDO getOrderById(Long id) {
        DynamicDataSourceContextHolder.setContextKey(DataSourceConstants.DS_KEY_SLAVE);
        OrderDO orderDO = orderDao.getOrderById(id);
        DynamicDataSourceContextHolder.removeContextKey();
        return orderDO;
    }
  • 先指定对应的数据源
  • 运行完sql之后移除数据源
2、通过AOP动态获取数据源

项目地址

https://github.com/zhengguofeng1998/DynamicDataSource/tree/master/ThirdDemo

2.1、项目结构

2.2、自定义注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {
    
    String value() default DataSourceConstants.DS_KEY_PRIMARY;
}

2.3、AOP切面
@Aspect
@Component
public class DynamicDataSourceAspect {
    //        @Pointcut("execution(* com.zgf.aop.Buy.buy(double)) && args(price)")
    @Pointcut("@annotation(com.zgf.springcloud.annotation.DS)")
    public void dataSourcePointCut() {

    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String dsKey = getDSAnnotation(joinPoint).value();
        DynamicDataSourceContextHolder.setContextKey(dsKey);
        try {
            return joinPoint.proceed();
        } finally {
            DynamicDataSourceContextHolder.removeContextKey();
        }
    }

    
    private DS getDSAnnotation(ProceedingJoinPoint joinPoint) {
        Class targetClass = joinPoint.getTarget().getClass();
        DS dsAnnotation = targetClass.getAnnotation(DS.class);
        // 先判断类的注解,再判断方法注解
        if (Objects.nonNull(dsAnnotation)) {
            return dsAnnotation;
        } else {
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            return methodSignature.getMethod().getAnnotation(DS.class);
        }
    }
}
2.4、如何使用
    @Override
    @DS(DataSourceConstants.DS_KEY_SLAVE)
    public OrderDO getOrderById(Long id) {
        OrderDO orderDO = orderDao.getOrderById(id);
        return orderDO;
    }
  • 在方法上添加@DS注解指定对应的数据源的key
3、客户可通过接口直接配置数据源 3.1、代码
@GetMapping("/addDataSource")
public String addDataSource() {
    Map myTargetDataSources = dynamicDataSource.getMyTargetDataSources();
    DruidDataSource druidDataSource = new DruidDataSource();
    druidDataSource.setUrl(url);
    druidDataSource.setUsername(username);
    druidDataSource.setPassword(password);
    druidDataSource.setDriverClassName(driverClassName);
    druidDataSource = DynamicDataSourceConfig.dataSource(druidDataSource);
    myTargetDataSources.put("storage", druidDataSource);
    dynamicDataSource.setTargetDataSources(myTargetDataSources);
    dynamicDataSource.afterPropertiesSet();
    return "添加数据源成功";
}
  • 因为DruidDataSource实现了AbstractRoutingDataSource,只需要把数据源放入到父类中,然后使用的时候再获取即可。
  • 调用setTargetDataSources方法,设置新加入的数据源
  • 使用和之前一样可通过注解进行配置
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/821268.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号