温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

SpringBoot中怎样配置多数据源

发布时间:2021-08-03 15:36:47 来源:亿速云 阅读:207 作者:Leah 栏目:编程语言
# SpringBoot中怎样配置多数据源 ## 目录 - [一、多数据源应用场景](#一多数据源应用场景) - [二、SpringBoot多数据源核心原理](#二springboot多数据源核心原理) - [三、基于AbstractRoutingDataSource的实现方案](#三基于abstractroutingdatasource的实现方案) - [3.1 基础环境准备](#31-基础环境准备) - [3.2 数据源配置类](#32-数据源配置类) - [3.3 动态数据源切换](#33-动态数据源切换) - [3.4 事务管理配置](#34-事务管理配置) - [四、多数据源与MyBatis集成](#四多数据源与mybatis集成) - [4.1 MyBatis配置分离](#41-mybatis配置分离) - [4.2 多数据源Mapper扫描](#42-多数据源mapper扫描) - [五、Spring Data JPA多数据源配置](#五spring-data-jpa多数据源配置) - [5.1 JPA实体管理器配置](#51-jpa实体管理器配置) - [5.2 事务管理器配置](#52-事务管理器配置) - [六、多数据源与分布式事务](#六多数据源与分布式事务) - [6.1 JTA实现方案](#61-jta实现方案) - [6.2 Seata集成方案](#62-seata集成方案) - [七、多数据源性能优化](#七多数据源性能优化) - [7.1 连接池配置](#71-连接池配置) - [7.2 读写分离实现](#72-读写分离实现) - [八、常见问题解决方案](#八常见问题解决方案) - [九、生产环境最佳实践](#九生产环境最佳实践) - [十、总结与展望](#十总结与展望) ## 一、多数据源应用场景 在现代企业级应用开发中,多数据源配置已成为常见需求,主要应用场景包括: 1. **业务数据隔离** 不同业务模块使用独立数据库实例,例如用户中心、订单系统分别部署在不同MySQL实例 2. **读写分离架构** 主库负责写操作,多个从库处理读请求,如电商系统商品查询与订单写入分离 3. **多数据库类型混合** 事务数据使用MySQL,文档数据存储MongoDB,缓存使用Redis的多存储引擎组合 4. **分库分表中间件集成** 配合ShardingSphere等中间件实现水平分库时的数据源路由 5. **多租户SaaS系统** 每个租户使用独立数据库实例,通过数据源动态切换实现租户隔离 6. **数据迁移与同步** 双写场景下需要同时操作新旧两个数据库系统 7. **异构数据源整合** 需要同时访问传统关系型数据库和新型时序数据库(如InfluxDB)的场景 ```java // 典型的多租户数据源选择逻辑示例 public class TenantDataSourceSelector { public static String determineDataSourceKey() { String tenantId = TenantContext.getCurrentTenant(); return "ds_" + tenantId; } } 

二、SpringBoot多数据源核心原理

SpringBoot自动配置的数据源机制基于DataSourceAutoConfiguration,实现多数据源需要突破几个技术关键点:

  1. 自动配置覆盖
    通过@Primary注解标记主数据源,禁用默认的自动配置
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class }) 
  1. AbstractRoutingDataSource
    Spring提供的抽象路由数据源,通过determineCurrentLookupKey()方法动态选择数据源
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSourceKey(); } } 
  1. 事务管理扩展
    需要为每个数据源配置独立的事务管理器,并通过@Transactional注解指定

  2. MyBatis/JPA集成
    需要为每个数据源创建独立的SqlSessionFactory或EntityManagerFactory

  3. 连接池管理
    每个数据源应使用独立的连接池配置(如HikariCP、Druid)

SpringBoot中怎样配置多数据源

三、基于AbstractRoutingDataSource的实现方案

3.1 基础环境准备

  1. 添加Maven依赖:
<dependencies> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>4.0.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- 根据实际需要添加MyBatis或JPA依赖 --> </dependencies> 
  1. 配置文件application.yml:
spring: datasource: master: jdbc-url: jdbc:mysql://localhost:3306/master_db username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver slave: jdbc-url: jdbc:mysql://localhost:3307/slave_db username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver 

3.2 数据源配置类

@Configuration public class DataSourceConfig { @Bean @ConfigurationProperties("spring.datasource.master") public DataSource masterDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties("spring.datasource.slave") public DataSource slaveDataSource() { return DataSourceBuilder.create().build(); } @Bean @Primary public DataSource dynamicDataSource(DataSource masterDataSource, DataSource slaveDataSource) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put("master", masterDataSource); targetDataSources.put("slave", slaveDataSource); DynamicDataSource dynamicDataSource = new DynamicDataSource(); dynamicDataSource.setTargetDataSources(targetDataSources); dynamicDataSource.setDefaultTargetDataSource(masterDataSource); return dynamicDataSource; } } 

3.3 动态数据源切换

public class DataSourceContextHolder { private static final ThreadLocal<String> CONTEXT = new ThreadLocal<>(); public static void setDataSourceKey(String key) { CONTEXT.set(key); } public static String getDataSourceKey() { return CONTEXT.get(); } public static void clear() { CONTEXT.remove(); } } // 使用AOP实现注解式切换 @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource { String value() default "master"; } @Aspect @Component public class DataSourceAspect { @Before("@annotation(ds)") public void beforeSwitchDataSource(DataSource ds) { DataSourceContextHolder.setDataSourceKey(ds.value()); } @After("@annotation(ds)") public void afterSwitchDataSource(DataSource ds) { DataSourceContextHolder.clear(); } } 

3.4 事务管理配置

@Configuration @EnableTransactionManagement public class TransactionConfig { @Bean public PlatformTransactionManager transactionManager(DynamicDataSource dataSource) { return new DataSourceTransactionManager(dataSource); } // 多事务管理器配置示例 @Bean public PlatformTransactionManager masterTxManager(@Qualifier("masterDataSource") DataSource ds) { return new DataSourceTransactionManager(ds); } @Bean public PlatformTransactionManager slaveTxManager(@Qualifier("slaveDataSource") DataSource ds) { return new DataSourceTransactionManager(ds); } } 

四、多数据源与MyBatis集成

4.1 MyBatis配置分离

@Configuration @MapperScan(basePackages = "com.example.mapper.master", sqlSessionFactoryRef = "masterSqlSessionFactory") public class MasterMyBatisConfig { @Bean public SqlSessionFactory masterSqlSessionFactory( @Qualifier("masterDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setMapperLocations( new PathMatchingResourcePatternResolver() .getResources("classpath:mapper/master/*.xml")); return sessionFactory.getObject(); } @Bean public SqlSessionTemplate masterSqlSessionTemplate( @Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } } 

4.2 多数据源Mapper扫描

// 主数据源Mapper接口 @Mapper public interface MasterUserMapper { @Select("SELECT * FROM users WHERE id = #{id}") User selectById(Long id); } // 从数据源Mapper接口 @Mapper public interface SlaveOrderMapper { @Select("SELECT * FROM orders WHERE user_id = #{userId}") List<Order> selectByUserId(Long userId); } // 使用示例 @Service public class BusinessService { private final MasterUserMapper masterUserMapper; private final SlaveOrderMapper slaveOrderMapper; @DataSource("slave") public List<Order> getUserOrders(Long userId) { User user = masterUserMapper.selectById(userId); return slaveOrderMapper.selectByUserId(userId); } } 

五、Spring Data JPA多数据源配置

5.1 JPA实体管理器配置

@Configuration @EnableJpaRepositories( basePackages = "com.example.repository.primary", entityManagerFactoryRef = "primaryEntityManagerFactory", transactionManagerRef = "primaryTransactionManager" ) public class PrimaryJpaConfig { @Primary @Bean public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("primaryDataSource") DataSource dataSource) { return builder .dataSource(dataSource) .packages("com.example.entity.primary") .persistenceUnit("primaryPersistenceUnit") .properties(jpaProperties()) .build(); } private Map<String, Object> jpaProperties() { Map<String, Object> props = new HashMap<>(); props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); props.put("hibernate.hbm2ddl.auto", "update"); return props; } } 

5.2 事务管理器配置

@Configuration public class JpaTransactionConfig { @Primary @Bean public PlatformTransactionManager primaryTransactionManager( @Qualifier("primaryEntityManagerFactory") EntityManagerFactory emf) { return new JpaTransactionManager(emf); } @Bean public PlatformTransactionManager secondaryTransactionManager( @Qualifier("secondaryEntityManagerFactory") EntityManagerFactory emf) { return new JpaTransactionManager(emf); } } 

六、多数据源与分布式事务

6.1 JTA实现方案

@Configuration @EnableTransactionManagement public class JtaConfig { @Bean public UserTransaction userTransaction() throws Throwable { UserTransactionImp userTransaction = new UserTransactionImp(); userTransaction.setTransactionTimeout(300); return userTransaction; } @Bean public TransactionManager atomikosTransactionManager() { UserTransactionManager manager = new UserTransactionManager(); manager.setForceShutdown(false); return manager; } @Bean public JtaTransactionManager transactionManager( UserTransaction userTransaction, TransactionManager atomikosTransactionManager) { return new JtaTransactionManager(userTransaction, atomikosTransactionManager); } } 

6.2 Seata集成方案

  1. 添加Seata依赖:
<dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>1.5.1</version> </dependency> 
  1. 配置Seata数据源代理:
@Configuration public class SeataConfig { @Bean public DataSourceProxy masterDataSourceProxy(@Qualifier("masterDataSource") DataSource ds) { return new DataSourceProxy(ds); } @Bean public DataSourceProxy slaveDataSourceProxy(@Qualifier("slaveDataSource") DataSource ds) { return new DataSourceProxy(ds); } @Bean @Primary public DataSource dynamicDataSource(DataSourceProxy masterProxy, DataSourceProxy slaveProxy) { // 动态数据源配置 } } 

七、多数据源性能优化

7.1 连接池配置

spring: datasource: master: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000 slave: hikari: maximum-pool-size: 30 minimum-idle: 10 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000 

7.2 读写分离实现

public class ReadWriteDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly(); if(isReadOnly) { return "slave"; } return "master"; } } // 使用示例 @Service public class ProductService { @Transactional(readOnly = true) public Product getProduct(Long id) { // 自动路由到从库 } @Transactional public void updateProduct(Product product) { // 自动路由到主库 } } 

八、常见问题解决方案

  1. 事务失效问题

    • 确保@Transactional注解的方法被Spring代理
    • 检查事务管理器配置是否正确
  2. 数据源切换不生效

    • 检查AOP执行顺序,确保数据源切换先于事务开启
    • 添加@Order(Ordered.HIGHEST_PRECEDENCE)到切面类
  3. 连接泄漏问题

    • 确保每次操作后调用DataSourceContextHolder.clear()
    • 配置Druid的removeAbandoned参数
  4. MyBatis缓存冲突

    • 为不同数据源配置独立的缓存实例
    • 在Mapper接口添加@CacheNamespace注解
  5. 分布式事务超时

    • 调整Seata的global.transaction.timeout参数
    • 优化业务逻辑减少事务执行时间

九、生产环境最佳实践

  1. 监控与告警

    • 集成Prometheus监控各数据源连接池状态
    • 配置关键指标告警(活跃连接数、等待连接数)
  2. 故障转移策略

    • 实现数据源健康检查机制
    • 配置备用数据源自动切换
  3. 性能调优

    • 根据压测结果调整连接池参数
    • 启用P6Spy监控SQL执行性能
  4. 安全规范

    • 使用Vault管理数据库凭据
    • 实现敏感数据加密存储
  5. 文档规范

    • 维护数据源切换决策矩阵
    • 记录各业务场景使用的事务策略

十、总结与展望

本文详细介绍了SpringBoot多数据源的完整实现方案,关键要点包括:

  1. 通过AbstractRoutingDataSource实现动态路由
  2. 结合AOP实现声明式数据源切换
  3. 多事务管理器的精细控制
  4. 与主流ORM框架的集成方案
  5. 分布式事务的解决方案

未来发展趋势:

  1. 云原生数据访问
    随着Service Mesh的普及,数据访问可能下沉到基础设施层

  2. 智能路由算法
    基于机器学习实现负载敏感的自动路由决策

  3. Serverless数据库集成
    服务器架构下的多数据源管理新范式

  4. 量子数据库连接
    未来量子计算环境下的新型数据源管理模式

最佳实践建议:对于新项目,建议从简单方案开始,随着业务复杂度增加逐步演进架构。大型系统可考虑使用ShardingSphere等专业中间件。

点击查看完整示例代码 “`

注:本文为技术方案概述,实际实施时需根据具体业务场景调整配置。由于篇幅限制,部分实现细节未完全展开,建议结合官方文档和示例代码进行实践。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI