若依框架(RuoYi)是一款基于Spring Boot和Spring Cloud的开源快速开发平台,广泛应用于企业级应用开发。在实际项目中,多数据源配置是一种常见的需求,例如主从数据库分离、不同业务模块使用不同的数据库等场景。本文将详细介绍如何在若依框架中实现多数据源配置。
多数据源是指在一个应用程序中同时连接多个数据库实例,并根据业务逻辑动态切换数据源的能力。多数据源配置的核心在于:
确保项目中已引入必要的依赖项。通常情况下,若依框架已经集成了Spring Boot的数据源相关依赖,但为了支持多数据源,可能需要额外引入spring-boot-starter-aop
用于AOP切面编程。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
在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
为每个数据源创建对应的配置类,并将其注册到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();
}
}
创建一个动态数据源切换的工具类,通过线程局部变量(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();
}
}
创建一个动态数据源类,根据线程局部变量中的值决定使用哪个数据源。
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSource();
}
}
将动态数据源注册到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;
}
}
通过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();
}
}
}
在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();
}
}
graph TD A[请求进入] --> B{判断数据源} B -->|未指定| C[使用默认数据源] B -->|指定| D[切换至指定数据源] D --> E[执行SQL] E --> F[恢复默认数据源]