interview
springboot
在 Spring Boot 中如何实现多数据源配置

SpringBoot 面试题, 在 Spring Boot 中如何实现多数据源配置?

SpringBoot 面试题, 在 Spring Boot 中如何实现多数据源配置?

QA

Step 1

Q:: 在 Spring Boot 中如何实现多数据源配置?

A:: 在 Spring Boot 中实现多数据源配置的步骤如下:

1. 添加依赖:在 pom.xml 文件中添加 Spring Boot Starter Data JPA 和相关数据库驱动的依赖。

 
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
 

2. 配置数据源:在 application.yml 文件中配置多个数据源。

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

3. 创建配置类:为每个数据源创建配置类,并标注 @Primary 注解指定主要数据源。

 
@Configuration
public class DataSourceConfig {
 
    @Primary
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }
 
    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
}
 

4. 配置事务管理器:为每个数据源配置事务管理器。

 
@Configuration
@EnableTransactionManagement
public class TransactionManagerConfig {
 
    @Primary
    @Bean(name = "primaryTransactionManager")
    public PlatformTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource primaryDataSource) {
        return new DataSourceTransactionManager(primaryDataSource);
    }
 
    @Bean(name = "secondaryTransactionManager")
    public PlatformTransactionManager secondaryTransactionManager(@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
        return new DataSourceTransactionManager(secondaryDataSource);
    }
}
 

5. 配置 JPA 实体管理器:为每个数据源配置 JPA 实体管理器。

 
@Configuration
@EnableJpaRepositories(
    basePackages = "com.example.primary.repository",
    entityManagerFactoryRef = "primaryEntityManagerFactory",
    transactionManagerRef = "primaryTransactionManager"
)
public class PrimaryDataSourceConfig {
 
    @Primary
    @Bean(name = "primaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(EntityManagerFactoryBuilder builder, @Qualifier("primaryDataSource") DataSource primaryDataSource) {
        return builder
                .dataSource(primaryDataSource)
                .packages("com.example.primary.entity")
                .persistenceUnit("primaryPU")
                .build();
    }
}
 
@Configuration
@EnableJpaRepositories(
    basePackages = "com.example.secondary.repository",
    entityManagerFactoryRef = "secondaryEntityManagerFactory",
    transactionManagerRef = "secondaryTransactionManager"
)
public class SecondaryDataSourceConfig {
 
    @Bean(name = "secondaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(EntityManagerFactoryBuilder builder, @Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
        return builder
                .dataSource(secondaryDataSource)
                .packages("com.example.secondary.entity")
                .persistenceUnit("secondaryPU")
                .build();
    }
}
 

Step 2

Q:: 如何在 Spring Boot 中动态切换数据源?

A:: 在 Spring Boot 中动态切换数据源可以通过实现 AbstractRoutingDataSource 类来实现。首先,定义一个自定义的 RoutingDataSource 类来确定当前使用的数据源。

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

然后,使用 ThreadLocal 存储当前数据源的信息。

 
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();
    }
}
 

最后,在配置类中定义多个数据源,并使用 DynamicRoutingDataSource

 
@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();
    }
 
    @Bean
    public DataSource dataSource() {
        DynamicRoutingDataSource routingDataSource = new DynamicRoutingDataSource();
        Map<Object, Object> dataSourceMap = new HashMap<>();
        dataSourceMap.put("primary", primaryDataSource());
        dataSourceMap.put("secondary", secondaryDataSource());
        routingDataSource.setTargetDataSources(dataSourceMap);
        routingDataSource.setDefaultTargetDataSource(primaryDataSource());
        return routingDataSource;
    }
}
 

用途

面试多数据源配置的目的是了解候选人对 Spring Boot 及其数据访问层的理解和掌握程度。在实际生产环境中,多数据源配置常用于以下场景:\n\n`1.` **读写分离**:通过配置多个数据源,可以将读操作和写操作分开,提高系统性能和数据库负载能力。\n`2.` **分库分表**:对于大规模数据,可以通过分库分表的方式来提高系统性能和数据访问效率。\n`3.` **多租户架构**:在 SaaS 应用中,不同租户的数据存储在不同的数据库中,使用多数据源配置可以方便地实现多租户数据隔离。\n`4.` **数据迁移**:在数据迁移过程中,需要同时访问旧数据库和新数据库,以确保数据迁移的正确性和完整性。\n\n

相关问题

🦆
Spring Boot 中的 @Primary 注解有什么作用?

@Primary 注解用于指定当一个接口有多个实现类时,优先选择被 @Primary 标注的那个类作为默认的实现。在多数据源配置中,用于标注主要数据源。

🦆
Spring Boot 中如何配置 JPA?

在 Spring Boot 中配置 JPA 需要以下步骤:

1. 添加依赖:在 pom.xml 文件中添加 Spring Boot Starter Data JPA 依赖。

2. 配置数据源:在 application.yml 文件中配置数据源信息。

3. 创建实体类:定义 JPA 实体类并使用 @Entity 注解标注。

4. 创建仓库接口:定义继承 JpaRepository 的仓库接口。

5. 配置 JPA 属性:在 application.yml 文件中配置 JPA 相关属性,如 hibernate.ddl-autoshow-sql 等。

🦆
Spring Boot 中如何实现事务管理?

在 Spring Boot 中实现事务管理的步骤如下:

1. 启用事务管理:在主类或配置类上添加 @EnableTransactionManagement 注解。

2. 配置事务管理器:定义 PlatformTransactionManager Bean。

3. 使用 @Transactional 注解:在需要事务管理的方法上添加 @Transactional 注解。