从8月份到现在,团队一直有一项资源整合迁移的任务。简单来说,原来的产品设计规划不合理,各业务组各做各的,导致各类核心数据分散于各个业务组。8月初资源整合方案落地并开始实施,我们组承担起了管控各类数据的任务,未来各业务组生产出的数据以及各业务组需要的数据都只有我们这一个入口。

由于涉及到不同类的数据,并且这些数据是分散在各个业务组不同项目的数据库中,而且迁移产生的逻辑代码也是临时性,写在不同的项目或写在某一项目中也不合理,所以我想到的是用最初的项目框架搭建一个新的项目,使用多数据源,直接访问各个项目的数据库获取源数据,也不需要其他项目组做什么配合工作,数据交接工作只需要给我们梳理清除各个表的关系即可,后续迁移完新项目也直接停止服务即可。

所以接下来写一篇总结,Spring Cloud框架中如何配置多数据源。其实和Spring Boot项目配置一样,只是Spring Cloud框架数据源切换的切面定义有所不同。

1. Maven依赖

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>3.2.0</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.1.10.RELEASE</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.13</version>
</dependency>

以上依赖主要是数据库相关的,Spring Cloud相关的依赖就不在这展示了,涉及的依赖包括像nacos注册中心、feign、ribbon等等。

2. 数据库类型定义

首先,把需要访问的所有数据库用一个枚举来定义,下面就用英文1-4表示4个不同的数据库。

其次,提供设置与访问数据源类型的方案,为切面设置不同的数据源使用。

public class DataSourceType {
	* 数据库类型
	public enum DataBaseType {
	    * 数据库1
	   one,
	    * 数据库2
	   two,
	    * 数据库3
	   three,
	    * 数据库4
     * 使用ThreadLocal保证线程安全
    private static final ThreadLocal<DataBaseType> TYPE = new ThreadLocal<>();
     * 往当前线程里设置数据源类型
     * @param dataBaseType 数据源类型
    public static void setDataBaseType(DataBaseType dataBaseType) {
        if (dataBaseType == null) {
            throw new NullPointerException();
        TYPE.set(dataBaseType);
     * 获取数据源类型
     * @return 返回数据源的类型
    public static DataBaseType getDataBaseType() {
        //默认使用数据库1
        return TYPE.get() == null ? DataBaseType.one : TYPE.get();
     * 清空数据类型
    public static void clearDataBaseType() {
        TYPE.remove();

3. 数据库配置

在配置文件中添加各个数据库的连接地址、用户名和密码等信息。

spring:
  datasource:
    one:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: ****
      username: ****
      password: ****
      queryTimeout: 10000
    two:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: ****
      username: ****
      password: ****
      queryTimeout: 10000
    three:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: ****
      username: ****
      password: ****
      queryTimeout: 10000
    four:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: ****
      username: ****
      password: ****
      queryTimeout: 10000

4. 多数据源核心配置类

@Configuration
//若扫描不到mapper,添加以下注解配置基础包即可
@MapperScan(basePackages = "XXX", sqlSessionFactoryRef = "SqlSessionFactory")
public class DataSourceConfig {
    @Primary
    @Bean(name = "oneDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.one")
    public DataSource getOneDateSource() {
        return DataSourceBuilder.create().build();
    @Bean(name = "twoDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.two")
    public DataSource getTwoDateSource() {
        return DataSourceBuilder.create().build();
    @Bean(name = "threeDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.three")
    public DataSource getThreeDateSource() {
        return DataSourceBuilder.create().build();
    @Bean(name = "fourDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.four")
    public DataSource getFourDateSource() {
        return DataSourceBuilder.create().build();
     * 装载多个数据库源
     * @param oneDataSource
     * @param twoDataSource
     * @param threeDataSource
     * @param fourDataSource
     * @return 返回数据源集合
    @Bean(name = "dynamicDataSource")
    public DynamicDataSource dataSource(@Qualifier("oneDataSource") DataSource oneDataSource,
                                        @Qualifier("twoDataSource") DataSource twoDataSource,
                                        @Qualifier("threeDataSource") DataSource threeDataSource,
                                        @Qualifier("fourDataSource") DataSource fourDataSource) {
        Map<Object, Object> targetDataSource = new HashMap<>(16);
        targetDataSource.put(DataSourceType.DataBaseType.one, oneDataSource);
        targetDataSource.put(DataSourceType.DataBaseType.two, twoDataSource);
        targetDataSource.put(DataSourceType.DataBaseType.three, threeDataSource);
        targetDataSource.put(DataSourceType.DataBaseType.four, fourDataSource);
        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSource);
        //默认数据源
        dataSource.setDefaultTargetDataSource(oneDataSource);
        return dataSource;
     * 装配数据源添加扫描mapper.xml文件的路径位置
     * @param dynamicDataSource 多数据库源对象
     * @return 返回sql会话工厂
    @Bean(name = "SqlSessionFactory")
    public SqlSessionFactory setSqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) throws Exception {
        // 导入mybatis sql session配置
        MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
        // 指明数据源
        sessionFactory.setDataSource(dynamicDataSource);
        // 指明mapper.xml位置(配置文件中指明的xml位置会失效用此方式代替,具体原因未知)
//        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/**/*Mapper.xml"));
        // 指明实体扫描(多个package用逗号或者分号分隔)
        sessionFactory.setTypeAliasesPackage("XXX");
        // 导入mybatis配置
        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setCacheEnabled(false);
        // 配置打印sql语句
        configuration.setLogImpl(StdOutImpl.class);
        // 添加分页功能
        configuration.addInterceptor(new PaginationInterceptor());
        sessionFactory.setConfiguration(configuration);
        return sessionFactory.getObject();
     * 注入事务管理
    @Bean
    public DataSourceTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);

5. 数据源切面

核心思想就是AOP,通过访问不同路径的包,做数据源切换。在Spring Cloud框架中,主要是通过不同的feign包来区分使用哪个数据源。

@Aspect
@Component
public class DataSourceAop {
     * 设定切面地址在所有调用以下包下的任意类的任意方法或接口时切换数据源成指定数据源
    @Before("execution(* com.XXX.feign.impl.one..*(..))")
    public void setDataSourceOne() {
        DataSourceType.setDataBaseType(DataSourceType.DataBaseType.one);
    @Before("execution(* com.XXX.feign.impl.two..*(..))")
    public void setDataSourceTwo() {
        DataSourceType.setDataBaseType(DataSourceType.DataBaseType.two);
    @Before("execution(* com.XXX.feign.impl.three..*(..))")
    public void setDataSourceThree() {
        DataSourceType.setDataBaseType(DataSourceType.DataBaseType.three);
    @Before("execution(* com.XXX.feign.impl.four..*(..))")
    public void setDataSourceFour() {
        DataSourceType.setDataBaseType(DataSourceType.DataBaseType.four);

以上就是Spring Cloud框架的步骤及核心代码。

从结果来看,当初用一个独立的项目配置多数据源还是非常正确的选择。因为各项目难免有不同的需求仍然在不断开发迭代中,迁移这项任务涉及多个项目本来就很复杂,所以这个多数据源项目还是起到了很大的帮助作用的。

工作中涉及一个资源整合迁移事项,需要将分散在各个业务组不同项目的数据库中的数据进行整合迁移至团队项目中,而且迁移产生的逻辑代码也是临时性,写在不同的项目或写在某一项目中也不合理,所以决定使用多数据源,直接访问各项目的数据库获取源数据。
1、枚举多数据-定义一一对应变量 /** * * 列出所有的数据key(常用数据库名称来命名) * 注意: * 1)这里数据数据库是一对一的 * 2)DatabaseType中的变量名称就是数据库的名称 */ public enum DatabaseType {   test1,test2} 2、将数据变量保存在线程变量中 /** * * 作用:1、保存一个线程安全的D...
本篇主要介绍springboot如何进行多数据配置,及一些设计思路。主要包含以下内容: 1、多数据通过注解动态切换; 2、通过配置文件开关,只启用一个数据; 3、springboot中使用多数据存在循环引用的问题。
配置好mysql的主从复制后,读写分离需要在代码层面实现,本实例采用spring boot集成mybatis的方式是实现,数据连接池使用druid 1、加入maven依赖,配置application.yml文件 pom.xml依赖jar <dependency> <groupId>org.springframework.boot<...
这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar
<groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency&
Spring Cloud配置数据可以使用 Spring Boot 提供的多数据支持。下面是一个简单的示例: 1. 首先,在 `application.properties` 或 `application.yml` 中配置数据的信息,例如: ```yaml spring.datasource.url=jdbc:mysql://localhost:3306/main_db spring.datasource.username=root spring.datasource.password=secret spring.datasource.driver-class-name=com.mysql.jdbc.Driver 2. 创建第二个数据配置类,例如 `SecondaryDataSourceConfig.java`: ```java @Configuration public class SecondaryDataSourceConfig { @Bean(name = "secondaryDataSource") @ConfigurationProperties(prefix = "spring.secondary.datasource") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); @Bean(name = "secondaryJdbcTemplate") public JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); 3. 在 `application.properties` 或 `application.yml` 中配置第二个数据的信息,例如: ```yaml spring.secondary.datasource.url=jdbc:mysql://localhost:3306/secondary_db spring.secondary.datasource.username=root spring.secondary.datasource.password=secret spring.secondary.datasource.driver-class-name=com.mysql.jdbc.Driver 4. 在需要使用第二个数据的地方注入 `JdbcTemplate`,例如: ```java @Autowired @Qualifier("secondaryJdbcTemplate") private JdbcTemplate secondaryJdbcTemplate; 这样,你就可以在 Spring Cloud配置并使用多个数据了。请注意,上述示例是基于 Spring Boot 和 JdbcTemplate 的,你可以根据自己的需求选择其他的数据访问方式,如 MyBatis、Hibernate 等。