广告
返回顶部
首页 > 资讯 > 后端开发 > Python >SpringBoot多数据源配置的全过程记录
  • 273
分享到

SpringBoot多数据源配置的全过程记录

2024-04-02 19:04:59 273人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录前言 配置文件 依赖 构建 AbstractRoutingDataSource 数据源切换 目录 总结 前言 多数据源的核心就是向 ioc 容器注入 AbstractRouti

前言

多数据源的核心就是向 ioc 容器注入 AbstractRoutingDataSource 和如何切换数据源。注入的方式可以是注册 BeanDefinition 或者是构建好的 Bean,切换数据源的方式可以是方法参数或者是注解切换(其他的没想象出来),具体由需求决定。

我的需求是统计多个库的数据,将结果写入另一个数据库,统计的数据库数量是不定的,无法通过 @Bean 直接注入,又是统计任务,DAO 层注解切换无法满足,因此选择注册(AbstractRoutingDataSource 的)BeanDefinition 和方法参数切换来实现。下面以统计统计中日韩用户到结果库为例。

配置文件

master 为结果库,其他为被统计的数据库(china、japan 可以用枚举唯一标识,当然也可以用 String):


dynamic:
  dataSources:
    master:
      driver-class-name: com.Mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/result?useUnicode=true&characterEncoding=utf8xxxxxxxx
      username: root
      passWord: 123456
    china:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/china?useUnicode=true&characterEncoding=utf8xxxxxxxx
      username: root
      password: 123456
    japan:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/japan?useUnicode=true&characterEncoding=utf8xxxxxxxx
      username: root
      password: 123456
    korea:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/korea?useUnicode=true&characterEncoding=utf8xxxxxxxx
      username: root
      password: 123456

对应的配置类:


package com.statistics.dynamicds.core.config;

import com.statistics.dynamicds.core.Country;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.util.Map;

import static com.statistics.dynamicds.core.config.MultiDataSourceProperties.PREFIX;

@Data
@Configuration
@ConfigurationProperties(prefix = PREFIX)
public class MultiDataSourceProperties {
  public static final String PREFIX = "dynamic";
  private Map<Country, DataSourceProperties> dataSources;

  @Data
  public static class DataSourceProperties {
    private String driverClassName;
    private String url;
    private String username;
    private String password;
  }
}
package com.statistics.dynamicds.core;

public enum Country {
  MASTER("master", 0),

  CHINA("china", 86),
  JAPAN("japan", 81),
  KOREA("korea", 82),
  // 其他国家省略

  private final String name;
  private final int id;

  Country(String name, int id) {
    this.name = name;
    this.id = id;
  }

  public int getId() {
    return id;
  }

  public String getName() {
    return name;
  }
}

依赖

ORM 用的 JPA,SpringBoot 版本为 2.3.7.RELEASE,通过 Lombok 简化 GetSet。


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

<dependency>
     <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
     <version>1.18.22</version>
     <scope>provided</scope>
</dependency>

构建 AbstractRoutingDataSource

Spring 的动态数据源需要注入 AbstractRoutingDataSource,因为配置文件中被统计数据源不是固定的,所以不能通过 @Bean 注解注入,需要手动构建。

要在启动类加上 @Import(MultiDataSourceImportBeanDefinitionReGIStrar.class)。

要在启动类加上 @Import(MultiDataSourceImportBeanDefinitionRegistrar.class)。

要在启动类加上 @Import(MultiDataSourceImportBeanDefinitionRegistrar.class),重要的事情写三行。


package com.statistics.dynamicds.autoconfig;

import com.statistics.dynamicds.core.DynamicDataSourceRouter;
import com.statistics.dynamicds.core.Country;
import com.statistics.dynamicds.core.config.MultiDataSourceProperties;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

import javax.annotation.Nonnull;
import java.util.Map;
import java.util.stream.Collectors;

import static com.statistics.dynamicds.core.config.MultiDataSourceProperties.PREFIX;

public class MultiDataSourceImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
  public static final String DATASOURCE_BEANNAME = "dynamicDataSourceRouter";
  private Environment environment;

  @Override
  public void registerBeanDefinitions(@Nonnull AnnotationMetadata importinGClaSSMetadata, BeanDefinitionRegistry registry) {
    MultiDataSourceProperties multiDataSourceProperties = Binder.get(environment)
            .bind(PREFIX, MultiDataSourceProperties.class)
            .orElseThrow(() -> new RuntimeException("no found dynamicds config"));
    final HikariDataSource[] defaultTargetDataSource = {null};
    Map<Country, HikariDataSource> targetDataSources = multiDataSourceProperties.getDataSources().entrySet().stream()
            .collect(Collectors.toMap(
                    Map.Entry::geTKEy,
                    entry -> {
              MultiDataSourceProperties.DataSourceProperties dataSourceProperties = entry.getValue();
              HikariDataSource dataSource = DataSourceBuilder.create()
                      .type(HikariDataSource.class)
                      .driverClassName(dataSourceProperties.getDriverClassName())
                      .url(dataSourceProperties.getUrl())
                      .username(dataSourceProperties.getUsername())
                      .password(dataSourceProperties.getPassword())
                      .build();
              dataSource.setPoolName("HikariPool-" + entry.getKey());
              if (Country.MASTER == entry.getKey()) {
                defaultTargetDataSource[0] = dataSource;
              }
              return dataSource;
            }));
    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DynamicDataSourceRouter.class)
            .addConstructorArgValue(defaultTargetDataSource[0])
            .addConstructorArgValue(targetDataSources)
            .getBeanDefinition();
    registry.registerBeanDefinition(DATASOURCE_BEANNAME, beanDefinition);
  }

  @Override
  public void setEnvironment(@Nonnull Environment environment) {
    this.environment = environment;
  }
}

上面代码中 MultiDataSourceProperties 不是由 @Resource 或者 @Autowired 获取的是因为 ImportBeanDefinitionRegistrar 执行的很早,此时 @ConfigurationProperties 的配置参数类还没有注入,因此要手动获取(加 @ConfigurationProperties 注解是为了使 IOC 容器中其他 Bean 能获取配置的 Country,以此来切换数据源)。

下面是 AbstractRoutingDataSource 的实现类 DynamicDataSourceRouter:


package com.statistics.dynamicds.core;

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

import java.util.Map;

public class DynamicDataSourceRouter extends AbstractRoutingDataSource {
  public DynamicDataSourceRouter(Object defaultTargetDataSource, Map<Object, Object> targetDataSources) {
    this.setDefaultTargetDataSource(defaultTargetDataSource);
    this.setTargetDataSources(targetDataSources);
  }

  @Override
  protected Object determineCurrentLookupKey() {
    return DataSourceContextHolder.getLookupKey();
  }
}

数据源切换

数据源的切换由 DataSourceContextHolder 和切面 DynamicDataSourceAspect 控制:


package com.statistics.dynamicds.core;

public class DataSourceContextHolder {
  private static final ThreadLocal<Country> HOLDER = ThreadLocal.withInitial(() -> Country.MASTER);

  public static void setLookupKey(Country lookUpKey) {
    HOLDER.set(lookUpKey);
  }

  public static Country getLookupKey() {
    return HOLDER.get();
  }

  public static void clear() {
    HOLDER.remove();
  }
}
package com.statistics.dynamicds.core;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DynamicDataSourceAspect {

  @Pointcut("execution(* com.statistics.dao..*.*(..))")
  void aspect() {

  }

  @Around("aspect()")
  public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    for (Object arg : joinPoint.getArgs()) {
      if (arg instanceof Country) {
        DataSourceContextHolder.setLookupKey((Country) arg);
        break;
      }
    }
    try {
      return joinPoint.proceed();
    }finally {
      DataSourceContextHolder.clear();
    }
  }
}

目录

.
└─com
    └─statistics
        │  StatisticsApplication.java
        │
        ├─dao
        │      UserDao.java
        │
        ├─dynamicds
        │  ├─autoconfig
        │  │      MultiDataSourceImportBeanDefinitionRegistrar.java
        │  │
        │  └─core
        │      │  DataSourceContextHolder.java
        │      │  DynamicDataSourceAspect.java
        │      │  DynamicDataSourceRouter.java
        │      │  Province.java
        │      │
        │      └─config
        │              MultiDataSourceProperties.java

总结

以上就完成了多数据源配置,使用时只需要按照在 dao 层的方法参数中加一个 Country 枚举就可以了。

如果无法用枚举标识数据源也可以换成 String,关于这个数据源的其他信息在内部类 DataSourceProperties 加一个 map 即可,总之就是按照自己的需求扩展。

--结束END--

本文标题: SpringBoot多数据源配置的全过程记录

本文链接: https://www.lsjlt.com/news/156519.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • SpringBoot多数据源配置的全过程记录
    目录前言 配置文件 依赖 构建 AbstractRoutingDataSource 数据源切换 目录 总结 前言 多数据源的核心就是向 IOC 容器注入 AbstractRouti...
    99+
    2022-11-12
  • SpringBoot多数据源配置的过程是什么
    本篇内容主要讲解“SpringBoot多数据源配置的过程是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SpringBoot多数据源配置的过程是什么”吧!前言多数据源的核心就是向 IOC 容...
    99+
    2023-06-25
  • springboot多数据源配置
    简介 开发当中经常会遇到需要进行多库多表数据整合的需求,在无法拆分项目的情况下,就需要在一个项目中配置多数据源,实现多库数据的整合。本文是在springboot框架的基础上进行的多数据源配置,可参考,也欢迎指正 1、第一步:applicat...
    99+
    2023-08-24
    spring boot mybatis java database
  • SpringBoot +DynamicDataSource切换多数据源的全过程
    目录固定多个数据源切换1.由于我这个版本的自带DynamicDataSource包2.在yml中配置两个数据源3.启动时启动连接池的方法获取4.载入各个连接池5.dynamicDat...
    99+
    2022-11-12
  • springboot mybatis druid配置多数据源教程
    目录1、项目代码结构2、导入基本依赖3、配置多数据源4、配置类5、启动类6、测试使用的表7、测试表对应的实体类8、持久层:dao层接口1、项目代码结构 2、导入基本依赖 记得需要导...
    99+
    2022-11-12
  • springboot怎么配置多数据源
    在Spring Boot中配置多个数据源可以通过以下步骤来实现: 在pom.xml文件中添加Spring Boot对多数据源的支...
    99+
    2023-10-23
    springboot
  • SpringBoot前后端json数据交互的全过程记录
    目录一、参考文献二、勇敢尝试三、最终选择交互方式总结一、参考文献 原生Ajax与JQuery Ajax SpringMVC接受JSON参数详解及常见错误总结 提交方式为 POST 时...
    99+
    2022-11-13
  • springboot全局配置文件与多环境配置的全过程
    目录1、全局配置文件2、多环境配置附:加载多环境配置总结1、全局配置文件 新建一个springboot项目它的resources目录下有一个application.propertie...
    99+
    2022-11-12
  • springboot下配置多数据源的方法
    一、springboot 简介SpringBoot使开发独立的,产品级别的基于Spring的应用变得非常简单,你只需"just run"。 我们为Spring平台及第三方库提 供开箱即用的设置,这样你就可以有条不紊地开始。多...
    99+
    2023-05-31
    spring boot 多数据源
  • springboot中如何配置多数据源
    这期内容当中小编将会给大家带来有关springboot中如何配置多数据源,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一、建库建表1.1 创建数据库db1和数据库db21.2 在数据库db1中创建表db1...
    99+
    2023-06-15
  • springboot打war包的全过程记录
    目录为什么要把SpringBoot打成war包springboot打war包分步指南总结为什么要把SpringBoot打成war包 正常情况下SpringBoot项目是以jar包的形...
    99+
    2022-11-13
  • SpringBoot多数据源配置详细教程(JdbcTemplate、mybatis)
    多数据源配置 首先是配置文件 这里采用yml配置文件,其他类型配置文件同理 我配置了两个数据源,一个名字叫ds1数据源,一个名字叫ds2数据源,如果你想配置更多的...
    99+
    2022-11-11
  • ruoyi(若依)配置多数据源(mysql+postgresql),rouyi(Springboot)多数据源设置
    一、除了MySQL驱动,我们还需要用到postgresql的驱动,所以我们先把驱动的依赖给导入进来 org.postgresql postgresql ...
    99+
    2023-08-17
    mysql postgresql spring boot
  • SpringBoot多数据源配置并通过注解实现动态切换数据源
    目录1. 环境准备1.1 数据库准备1.2 项目创建2. ThreadLocal类介绍3. AbstractRoutingDataSource类介绍4. 具体实现4.1 定义数据源枚...
    99+
    2022-11-13
    SpringBoot 动态切换数据源 SpringBoot 切换数据源
  • vue-cli配置使用Vuex的全过程记录
    目录前言安装使用模块化管理vuex状态持久化总结前言     在vue开发用我们常常会用到一些全局的数据,比如用户信息、用户权限、一...
    99+
    2022-11-12
  • Nginx反向代理配置的全过程记录
    一、准备工作 Linux系统安装Tomcat,使用默认端口8080,启动Tomcat服务器 可以正常访问 接下来想要通过Nginx反向代理,转发请求到Tomcat服务器。对外暴露...
    99+
    2022-11-12
  • Nginx配置ssl实现https的全过程记录
    目录一、安装Nginxssl模块1.检查2.安装3.再次检查二、部署ssl证书三、配置nginx.conf四、重启Nginx总结一、安装 Nginx ssl 模块 1.检查 检查是否...
    99+
    2022-11-13
  • Qt Creator配置opencv环境的全过程记录
    首先需要下载好相应的opencv+控件文件夹(注意不要有中文和空格): 到文件夹下的x86/bin 目录中拷贝所有的.dll文件(建议选择按类型排序,否则有可能拷贝漏了) 复制到...
    99+
    2022-11-13
  • springboot+springJdbc+postgresql 实现多数据源的配置
    背景 最近公司在服务拆迁,接口转移,相同的功能接口到要迁移到对应的服务中,因为时间比较赶,别问为什么没给时间,没人,没资源,但是活还是得干的,为了减少工作量和稳妥的需要分两步走 ...
    99+
    2022-11-12
  • springboot整合druid及多数据源配置
    前言 本篇主要分两部分 ①springboot整合druid的代码配置,以及druid的监控页面演示;②对实际场景中多数据源的配置使用进行讲解。 一、springboot整合druid的演示demo 可以用idea快速生成一个可运行的dem...
    99+
    2023-10-24
    spring boot java spring
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作