Spring Boot多数据源配置实战指南

发布于:2025-06-28 ⋅ 阅读:(14) ⋅ 点赞:(0)

在 Spring Boot 中实现多数据源拆分,需根据业务需求(如读写分离、模块隔离、多租户等)选择合适的方案。以下是核心思路及实现方式:


🔧 一、配置多个数据源

application.yml 中为每个数据源定义独立配置:

spring:
  datasource:
    primary:
      url: jdbc:mysql://localhost:3306/db1
      username: root
      password: 123456
      driver-class-name: com.mysql.cj.jdbc.Driver
    secondary:
      url: jdbc:mysql://localhost:3306/db2
      username: root
      password: 123456
      driver-class-name: com.mysql.cj.jdbc.Driver

通过 @Configuration 类创建多个 DataSource Bean:

@Configuration
public class DataSourceConfig {
    // 主数据源
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }
    // 从数据源
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
}

🔀 二、动态数据源切换(核心方案)

1. 继承 AbstractRoutingDataSource

自定义路由类,根据线程上下文选择数据源:

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceType(); // 返回数据源标识(如"primary")
    }
}
2. 管理数据源上下文

通过 ThreadLocal 存储当前线程的数据源标识:

public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
    
    public static void setDataSourceType(String dsType) {
        contextHolder.set(dsType);
    }
    public static String getDataSourceType() {
        return contextHolder.get();
    }
    public static void clear() {
        contextHolder.remove();
    }
}
3. 通过 AOP 自动切换

使用自定义注解(如 @DS("secondary"))标注方法,在切面中动态切换数据源:

@Aspect
@Component
public class DataSourceAspect {
    @Before("@annotation(ds)")
    public void switchDataSource(JoinPoint point, DS ds) {
        DataSourceContextHolder.setDataSourceType(ds.value()); 
    }
    @After("@annotation(ds)")
    public void restoreDataSource(DS ds) {
        DataSourceContextHolder.clear(); 
    }
}

📦 三、分包管理方案(替代方案)

将不同数据源的 DAO/Mapper 分别放入独立包路径,并为每个包配置独立的 SqlSessionFactory

@Configuration
@MapperScan(basePackages = "com.example.dao.primary", sqlSessionFactoryRef = "primarySqlSessionFactory")
public class PrimaryDataSourceConfig {
    @Bean
    public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        return bean.getObject();
    }
}

适用场景:业务模块边界清晰、数据源切换频率低。


⚠️ 四、事务管理

多数据源需单独配置事务管理器,避免跨库事务问题:

@Bean
public PlatformTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

注意:跨数据源操作如需强一致性,需引入分布式事务(如 Atomikos)。


🎯 五、适用场景

场景 方案推荐
读写分离 动态路由 + AOP 注解切换
业务模块隔离 分包管理 + 独立事务管理器
多租户 动态路由(按租户标识切换)
分库分表 ShardingSphere 集成

💡 关键注意事项

  1. 避免循环依赖:配置类中需明确 @Primary 数据源。
  2. 连接池配置:为每个 DataSource 单独设置连接池参数(如 HikariCP)。
  3. 性能监控:多数据源需独立监控 SQL 执行性能。
  4. 跨库查询限制:尽量避免跨库关联查询,可通过冗余字段或业务层拼接解决。

动态路由方案灵活性高但复杂度稍高,适合高频切换场景;分包方案更简单直观,适合模块化架构。根据实际业务负载和团队技术储备选择。


网站公告

今日签到

点亮在社区的每一天
去签到