# Spring Boot灵活数据源配置:注解驱动动态切换方案
在业务系统开发中,多数据源配置是常见需求,尤其是在微服务架构逐渐演进的背景下。Spring Boot提供了灵活的数据源配置机制,结合自定义注解可以优雅地实现数据源的动态切换,本文将详细介绍这一方案的技术实现。
## 一、多数据源应用场景分析
多数据源配置在以下场景中尤为重要:数据分库存储、读写分离架构、多租户系统以及不同业务模块使用独立数据库的情况。传统的单一数据源配置无法满足这些复杂需求,需要更灵活的解决方案。
## 二、基础数据源配置实现
首先,在`application.yml`中配置多个数据源信息:
```yaml
spring:
datasource:
primary:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_primary
username: root
password: 123456
secondary:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_secondary
username: root
password: 123456
```
创建数据源配置类,用于初始化多个数据源:
```java
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
}
```
## 三、动态数据源路由机制
实现动态数据源的核心是创建`AbstractRoutingDataSource`的子类,它能够根据当前上下文决定使用哪个数据源:
```java
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal
new ThreadLocal<>();
public static void setDataSourceKey(String dataSourceKey) {
CONTEXT_HOLDER.set(dataSourceKey);
}
public static String getDataSourceKey() {
return CONTEXT_HOLDER.get();
}
public static void clearDataSourceKey() {
CONTEXT_HOLDER.remove();
}
@Override
protected Object determineCurrentLookupKey() {
return getDataSourceKey();
}
}
```
## 四、自定义注解实现
创建`@DataSource`注解,用于标记需要特定数据源的方法或类:
```java
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value() default "primary";
}
```
通过AOP切面实现注解的拦截和数据源切换:
```java
@Aspect
@Component
@Order(-1)
public class DataSourceAspect {
<"u1.p5k3.org.cn"><"b8.p5k3.org.cn"><"x0.p5k3.org.cn">
@Around("@annotation(dataSource)")
public Object around(ProceedingJoinPoint point,
DataSource dataSource) throws Throwable {
String dsKey = dataSource.value();
DynamicDataSource.setDataSourceKey(dsKey);
try {
return point.proceed();
} finally {
DynamicDataSource.clearDataSourceKey();
}
}
}
```
## 五、完整配置与集成
配置动态数据源,将多个数据源集成到统一管理:
```java
@Configuration
@EnableTransactionManagement
public class DynamicDataSourceConfig {
@Bean
@Primary
public DataSource dataSource(DataSource primaryDataSource,
DataSource secondaryDataSource) {
Map
targetDataSources.put("primary", primaryDataSource);
targetDataSources.put("secondary", secondaryDataSource);
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setDefaultTargetDataSource(primaryDataSource);
dynamicDataSource.setTargetDataSources(targetDataSources);
return dynamicDataSource;
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
```
## 六、实际应用示例
在Service层使用注解切换数据源:
```java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
<"r4.p5k3.org.cn"><"k6.p5k3.org.cn"><"p3.p5k3.org.cn">
// 使用主数据源
public User getUserById(Long id) {
return userMapper.selectById(id);
}
// 使用次数据源
@DataSource("secondary")
public List
return userMapper.selectAll();
}
// 在同一个方法内切换不同数据源
@DataSource("primary")
public void syncUserData(Long userId) {
User primaryUser = userMapper.selectById(userId);
// 临时切换到次数据源
DynamicDataSource.setDataSourceKey("secondary");
try {
userMapper.insert(primaryUser);
} finally {
DynamicDataSource.clearDataSourceKey();
}
}
}
```
## 七、事务管理考虑
多数据源环境下的事务管理需要特别注意。建议使用分布式事务解决方案或确保每个方法只使用一个数据源。对于跨数据源的事务,可以考虑使用ChainedTransactionManager或JTA实现。
```java
@Service
public class OrderService {
@DataSource("primary")
@Transactional
public void createOrder(Order order) {
// 订单相关操作,使用主数据源
// 事务会自动绑定到当前数据源
}
}
```
## 八、性能优化与注意事项
1. **连接池配置**:为每个数据源单独配置合适的连接池参数
2. **线程安全**:确保ThreadLocal的清理,避免内存泄漏
3. **异常处理**:在切面中添加完善的异常处理机制
4. **监控支持**:集成监控系统,跟踪数据源使用情况
## 九、扩展与优化方向
本方案可以进一步扩展支持:
- 基于配置文件的数据源动态添加
- 数据源健康检查与自动切换
- 负载均衡策略支持
- 与MyBatis、JPA等持久层框架深度集成
通过本文介绍的方案,Spring Boot应用可以优雅地实现多数据源动态切换。这种注解驱动的方式保持了代码的整洁性,同时提供了足够的灵活性。在实际项目中,建议根据具体业务需求调整和扩展这一基础框架,确保系统稳定可靠。
这种实现方式平衡了配置的简洁性和功能的完备性,为复杂业务场景下的数据源管理提供了可靠的技术支撑。