欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

SpringBoot多数据源配置完整指南,

来源: javaer 分享于  点击 2326 次 点评:114

SpringBoot多数据源配置完整指南,


目录
  • 一、基础多数据源配置
    • 1. 添加依赖
    • 2. 配置多个数据源
    • 3. 配置数据源Bean
  • 二、JPA多数据源配置
    • 1. 配置主数据源JPA
    • 2. 配置次数据源JPA
  • 三、MyBatis多数据源配置
    • 1. 主数据源配置
    • 2. 次数据源配置
  • 四、动态数据源配置(运行时切换)
    • 1. 抽象路由数据源
    • 2. 数据源上下文持有者
    • 3. 配置动态数据源
    • 4. 使用AOP切换数据源
    • 5. 自定义注解
    • 6. 使用示例
  • 五、多数据源事务管理
    • 1. JTA分布式事务(Atomikos)
    • 2. 配置JTA数据源
    • 3. 使用分布式事务
  • 六、最佳实践
    • 七、常见问题解决

      一、基础多数据源配置

      1. 添加依赖

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-jpa</artifactId>
      </dependency>
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
      </dependency>
      <!-- 或者使用其他数据库驱动 -->
      

      2. 配置多个数据源

      # 主数据源
      spring.datasource.primary.url=jdbc:mysql://localhost:3306/db1
      spring.datasource.primary.username=root
      spring.datasource.primary.password=123456
      spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
      
      # 次数据源
      spring.datasource.secondary.url=jdbc:mysql://localhost:3306/db2
      spring.datasource.secondary.username=root
      spring.datasource.secondary.password=123456
      spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
      

      3. 配置数据源Bean

      @Configuration
      public class DataSourceConfig {
      
          // 主数据源
          @Bean
          @Primary
          @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();
          }
      }
      

      二、JPA多数据源配置

      1. 配置主数据源JPA

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

      2. 配置次数据源JPA

      @Configuration
      @EnableTransactionManagement
      @EnableJpaRepositories(
          basePackages = "com.example.repository.secondary",
          entityManagerFactoryRef = "secondaryEntityManagerFactory",
          transactionManagerRef = "secondaryTransactionManager"
      )
      public class SecondaryJpaConfig {
          
          @Autowired @Qualifier("secondaryDataSource")
          private DataSource secondaryDataSource;
          
          @Bean
          public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
                  EntityManagerFactoryBuilder builder) {
              return builder
                  .dataSource(secondaryDataSource)
                  .packages("com.example.entity.secondary")
                  .persistenceUnit("secondaryPersistenceUnit")
                  .properties(jpaProperties())
                  .build();
          }
          
          private Map<String, Object> jpaProperties() {
              Map<String, Object> props = new HashMap<>();
              props.put("hibernate.hbm2ddl.auto", "update");
              props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
              return props;
          }
          
          @Bean
          public PlatformTransactionManager secondaryTransactionManager(
                  @Qualifier("secondaryEntityManagerFactory") EntityManagerFactory emf) {
              return new JpaTransactionManager(emf);
          }
      }
      

      三、MyBatis多数据源配置

      1. 主数据源配置

      @Configuration
      @MapperScan(
          basePackages = "com.example.mapper.primary",
          sqlSessionFactoryRef = "primarySqlSessionFactory"
      )
      public class PrimaryMyBatisConfig {
      
          @Primary
          @Bean
          @ConfigurationProperties(prefix = "spring.datasource.primary")
          public DataSource primaryDataSource() {
              return DataSourceBuilder.create().build();
          }
      
          @Primary
          @Bean
          public SqlSessionFactory primarySqlSessionFactory(
                  @Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
              SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
              sessionFactory.setDataSource(dataSource);
              sessionFactory.setMapperLocations(
                  new PathMatchingResourcePatternResolver()
                      .getResources("classpath:mapper/primary/*.xml"));
              return sessionFactory.getObject();
          }
      
          @Primary
          @Bean
          public SqlSessionTemplate primarySqlSessionTemplate(
                  @Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
              return new SqlSessionTemplate(sqlSessionFactory);
          }
      }
      

      2. 次数据源配置

      @Configuration
      @MapperScan(
          basePackages = "com.example.mapper.secondary",
          sqlSessionFactoryRef = "secondarySqlSessionFactory"
      )
      public class SecondaryMyBatisConfig {
      
          @Bean
          @ConfigurationProperties(prefix = "spring.datasource.secondary")
          public DataSource secondaryDataSource() {
              return DataSourceBuilder.create().build();
          }
      
          @Bean
          public SqlSessionFactory secondarySqlSessionFactory(
                  @Qualifier("secondaryDataSource") DataSource dataSource) throws Exception {
              SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
              sessionFactory.setDataSource(dataSource);
              sessionFactory.setMapperLocations(
                  new PathMatchingResourcePatternResolver()
                      .getResources("classpath:mapper/secondary/*.xml"));
              return sessionFactory.getObject();
          }
      
          @Bean
          public SqlSessionTemplate secondarySqlSessionTemplate(
                  @Qualifier("secondarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
              return new SqlSessionTemplate(sqlSessionFactory);
          }
      }
      

      四、动态数据源配置(运行时切换)

      1. 抽象路由数据源

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

      2. 数据源上下文持有者

      public class DataSourceContextHolder {
      
          private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
      
          public static void setDataSourceType(String dataSourceType) {
              contextHolder.set(dataSourceType);
          }
      
          public static String getDataSourceType() {
              return contextHolder.get();
          }
      
          public static void clearDataSourceType() {
              contextHolder.remove();
          }
      }
      

      3. 配置动态数据源

      @Configuration
      public class DynamicDataSourceConfig {
      
          @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();
          }
      
          @Primary
          @Bean
          public DataSource dynamicDataSource(
                  @Qualifier("primaryDataSource") DataSource primaryDataSource,
                  @Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
              
              Map<Object, Object> targetDataSources = new HashMap<>();
              targetDataSources.put("primary", primaryDataSource);
              targetDataSources.put("secondary", secondaryDataSource);
              
              DynamicDataSource dynamicDataSource = new DynamicDataSource();
              dynamicDataSource.setTargetDataSources(targetDataSources);
              dynamicDataSource.setDefaultTargetDataSource(primaryDataSource);
              
              return dynamicDataSource;
          }
      }
      

      4. 使用AOP切换数据源

      @Aspect
      @Component
      public class DataSourceAspect {
      
          @Pointcut("@annotation(com.example.annotation.TargetDataSource)")
          public void dataSourcePointCut() {}
      
          @Before("dataSourcePointCut()")
          public void before(JoinPoint point) {
              MethodSignature signature = (MethodSignature) point.getSignature();
              Method method = signature.getMethod();
              TargetDataSource ds = method.getAnnotation(TargetDataSource.class);
              
              if (ds == null) {
                  DataSourceContextHolder.setDataSourceType("primary");
              } else {
                  DataSourceContextHolder.setDataSourceType(ds.value());
              }
          }
      
          @After("dataSourcePointCut()")
          public void after(JoinPoint point) {
              DataSourceContextHolder.clearDataSourceType();
          }
      }
      

      5. 自定义注解

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

      6. 使用示例

      @Service
      public class UserService {
      
          @Autowired
          private UserMapper userMapper;
          
          // 使用主数据源
          public User getPrimaryUser(Long id) {
              return userMapper.selectById(id);
          }
          
          // 使用次数据源
          @TargetDataSource("secondary")
          public User getSecondaryUser(Long id) {
              return userMapper.selectById(id);
          }
      }
      

      五、多数据源事务管理

      1. JTA分布式事务(Atomikos)

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

      2. 配置JTA数据源

      # 主数据源
      spring.jta.atomikos.datasource.primary.unique-resource-name=primaryDS
      spring.jta.atomikos.datasource.primary.xa-data-source-class-name=com.mysql.cj.jdbc.MysqlXADataSource
      spring.jta.atomikos.datasource.primary.xa-properties.url=jdbc:mysql://localhost:3306/db1
      spring.jta.atomikos.datasource.primary.xa-properties.user=root
      spring.jta.atomikos.datasource.primary.xa-properties.password=123456
      
      # 次数据源
      spring.jta.atomikos.datasource.secondary.unique-resource-name=secondaryDS
      spring.jta.atomikos.datasource.secondary.xa-data-source-class-name=com.mysql.cj.jdbc.MysqlXADataSource
      spring.jta.atomikos.datasource.secondary.xa-properties.url=jdbc:mysql://localhost:3306/db2
      spring.jta.atomikos.datasource.secondary.xa-properties.user=root
      spring.jta.atomikos.datasource.secondary.xa-properties.password=123456
      

      3. 使用分布式事务

      @Service
      public class OrderService {
      
          @Transactional // 跨数据源事务
          public void placeOrder(Order order) {
              // 操作主数据源
              primaryRepository.save(order);
              
              // 操作次数据源
              auditRepository.logOrder(order);
              
              // 如果此处抛出异常,两个操作都会回滚
          }
      }
      

      六、最佳实践

      1. 命名规范

        • 为每个数据源使用清晰的命名(如customerDS, orderDS)
        • 包结构按数据源分离(com.example.repository.primary / .secondary)
      2. 连接池配置

      spring.datasource.primary.hikari.maximum-pool-size=10
      spring.datasource.secondary.hikari.maximum-pool-size=5
      
      1. 监控指标

        • 为每个数据源配置独立的监控
        • 使用Spring Actuator暴露数据源健康指标
      2. 性能考虑

        • 高频访问的数据源使用更大的连接池
        • 读写分离场景考虑主从数据源
      3. 测试策略

        • 为每个数据源编写独立的测试类
        • 测试跨数据源事务的回滚行为

      七、常见问题解决

      问题1:循环依赖

      // 解决方法:使用@DependsOn
      @Bean
      @DependsOn("dynamicDataSource")
      public PlatformTransactionManager transactionManager() {
          return new DataSourceTransactionManager(dynamicDataSource());
      }
      

      问题2:MyBatis缓存冲突

      // 解决方法:为每个SqlSessionFactory配置独立的缓存环境
      sqlSessionFactory.setConfiguration(configuration);
      configuration.setEnvironment(new Environment(
          "primaryEnv", 
          transactionFactory, 
          dataSource
      ));
      

      问题3:事务传播行为异常

      // 解决方法:明确指定事务管理器
      @Transactional(transactionManager = "primaryTransactionManager")
      public void primaryOperation() {...}
      

      通过以上配置,Spring Boot应用可以灵活地支持多数据源场景,无论是简单的多库连接还是复杂的动态数据源切换需求。根据实际业务场景选择最适合的配置方式,并注意事务管理和性能调优。

      以上就是SpringBoot多数据源配置完整指南的详细内容,更多关于SpringBoot多数据源配置的资料请关注3672js教程其它相关文章!

      您可能感兴趣的文章:
      • springboot项目如何配置多数据源
      • SpringBoot实现JPA多数据源配置小结
      • SpringBoot实现多数据源配置的示例详解
      • Springboot+aop实现配置多数据源的示例代码
      • 一文详解SpringBoot Redis多数据源配置
      相关栏目:

      用户点评