若依框架如何实现多数据源配置

2025-06发布2次浏览

若依框架(RuoYi)是一款基于Spring Boot和Spring Cloud的开源快速开发平台,广泛应用于企业级应用开发。在实际项目中,多数据源配置是一种常见的需求,例如主从数据库分离、不同业务模块使用不同的数据库等场景。本文将详细介绍如何在若依框架中实现多数据源配置。


一、多数据源的基本概念

多数据源是指在一个应用程序中同时连接多个数据库实例,并根据业务逻辑动态切换数据源的能力。多数据源配置的核心在于:

  1. 数据源注册:将多个数据源注册到Spring容器中。
  2. 动态切换:通过拦截器或注解的方式,在运行时动态选择需要使用的数据源。
  3. 事务管理:确保每个数据源的事务独立性。

二、若依框架中实现多数据源的步骤

1. 引入依赖

确保项目中已引入必要的依赖项。通常情况下,若依框架已经集成了Spring Boot的数据源相关依赖,但为了支持多数据源,可能需要额外引入spring-boot-starter-aop用于AOP切面编程。

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

2. 配置多个数据源

application.yml中定义多个数据源的配置信息。例如:

spring:
  datasource:
    master:
      url: jdbc:mysql://localhost:3306/master_db?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
      username: root
      password: 123456
      driver-class-name: com.mysql.cj.jdbc.Driver
    slave:
      url: jdbc:mysql://localhost:3306/slave_db?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
      username: root
      password: 123456
      driver-class-name: com.mysql.cj.jdbcDriver

3. 创建数据源配置类

为每个数据源创建对应的配置类,并将其注册到Spring容器中。

主数据源配置
@Configuration
@Primary // 标记为主数据源
public class MasterDataSourceConfig {
    @Bean(name = "masterDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }
}
从数据源配置
@Configuration
public class SlaveDataSourceConfig {
    @Bean(name = "slaveDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }
}

4. 动态数据源切换

创建一个动态数据源切换的工具类,通过线程局部变量(ThreadLocal)存储当前线程使用的数据源名称。

public class DynamicDataSourceContextHolder {
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    public static void setDataSource(String dataSourceName) {
        CONTEXT_HOLDER.set(dataSourceName);
    }

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

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

5. 定义动态数据源

创建一个动态数据源类,根据线程局部变量中的值决定使用哪个数据源。

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSource();
    }
}

6. 注册动态数据源

将动态数据源注册到Spring容器中,并绑定所有数据源。

@Configuration
public class DataSourceConfig {
    @Autowired
    @Qualifier("masterDataSource")
    private DataSource masterDataSource;

    @Autowired
    @Qualifier("slaveDataSource")
    private DataSource slaveDataSource;

    @Bean
    public DynamicDataSource dataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", masterDataSource);
        targetDataSources.put("slave", slaveDataSource);

        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource); // 默认使用主数据源
        dynamicDataSource.setTargetDataSources(targetDataSources);

        return dynamicDataSource;
    }
}

7. 切换数据源的AOP实现

通过AOP拦截器实现动态数据源切换。定义一个自定义注解@DataSource,用于标记需要切换数据源的方法。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface DataSource {
    String value() default "";
}

编写AOP切面类:

@Aspect
@Component
public class DataSourceAspect {
    @Around("@annotation(dataSource)")
    public Object around(ProceedingJoinPoint point, DataSource dataSource) throws Throwable {
        String ds = dataSource.value();
        if (StringUtils.isNotEmpty(ds)) {
            DynamicDataSourceContextHolder.setDataSource(ds);
        }
        try {
            return point.proceed();
        } finally {
            DynamicDataSourceContextHolder.clearDataSource();
        }
    }
}

8. 使用示例

在Service层方法上添加@DataSource注解,指定需要切换的数据源。

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @DataSource("master")
    public List<User> getUsersFromMaster() {
        return userMapper.selectAll();
    }

    @DataSource("slave")
    public List<User> getUsersFromSlave() {
        return userMapper.selectAll();
    }
}

三、扩展讨论

  1. 事务管理:多数据源场景下,每个数据源的事务是独立的,需确保不会因事务传播机制导致问题。
  2. 性能优化:对于读写分离场景,可以结合缓存技术减少对从库的访问压力。
  3. 监控与日志:在切换数据源时,建议记录日志以便排查问题。
graph TD
    A[请求进入] --> B{判断数据源}
    B -->|未指定| C[使用默认数据源]
    B -->|指定| D[切换至指定数据源]
    D --> E[执行SQL]
    E --> F[恢复默认数据源]