Java面试必备:在Spring Boot中实现多数据源配置

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


引言

在现代企业应用开发中,一个应用需要连接多个数据库的场景越来越常见。Spring Boot提供了灵活的方式来实现多数据源配置,本文将详细介绍如何在Spring Boot项目中配置和使用多个数据源。

一、多数据源的应用场景

多数据源配置通常用于以下场景:

  • 读写分离(主从数据库)
  • 微服务架构中访问多个服务数据库
  • 分库分表场景
  • 访问异构数据库(如同时使用MySQL和Oracle)

二、基础配置实现

1. 添加依赖

首先,在pom.xml中添加必要的依赖:

<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. 配置多个数据源

application.propertiesapplication.yml中配置多个数据源:

# 主数据源配置
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. 创建数据源配置类

@Configuration
public class DataSourceConfig {

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

三、多数据源工作流程

应用启动
读取配置文件
创建Primary数据源
创建Secondary数据源
Primary事务管理器
Secondary事务管理器
Service层使用

四、JPA与多数据源集成

1. 配置主数据源的JPA

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "primaryEntityManagerFactory",
        transactionManagerRef = "primaryTransactionManager",
        basePackages = {"com.example.repository.primary"}
)
public class PrimaryJpaConfig {
    
    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primaryDataSource;

    @Bean(name = "primaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
            EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(primaryDataSource)
                .packages("com.example.entity.primary")
                .persistenceUnit("primary")
                .build();
    }

    @Bean(name = "primaryTransactionManager")
    public PlatformTransactionManager primaryTransactionManager(
            @Qualifier("primaryEntityManagerFactory") EntityManagerFactory primaryEntityManagerFactory) {
        return new JpaTransactionManager(primaryEntityManagerFactory);
    }
}

2. 配置次数据源的JPA

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "secondaryEntityManagerFactory",
        transactionManagerRef = "secondaryTransactionManager",
        basePackages = {"com.example.repository.secondary"}
)
public class SecondaryJpaConfig {
    
    @Autowired
    @Qualifier("secondaryDataSource")
    private DataSource secondaryDataSource;

    @Bean(name = "secondaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
            EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(secondaryDataSource)
                .packages("com.example.entity.secondary")
                .persistenceUnit("secondary")
                .build();
    }

    @Bean(name = "secondaryTransactionManager")
    public PlatformTransactionManager secondaryTransactionManager(
            @Qualifier("secondaryEntityManagerFactory") EntityManagerFactory secondaryEntityManagerFactory) {
        return new JpaTransactionManager(secondaryEntityManagerFactory);
    }
}

五、MyBatis与多数据源集成

1. 配置主数据源的MyBatis

@Configuration
@MapperScan(basePackages = "com.example.mapper.primary", sqlSessionFactoryRef = "primarySqlSessionFactory")
public class PrimaryMyBatisConfig {

    @Bean(name = "primarySqlSessionFactory")
    public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/primary/*.xml"));
        return bean.getObject();
    }

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

    @Bean(name = "primarySqlSessionTemplate")
    public SqlSessionTemplate primarySqlSessionTemplate(
            @Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

六、动态数据源切换

对于更复杂的场景,可以实现动态数据源路由:

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceType();
    }
}

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

动态数据源切换流程:

Client Service DataSourceRouter PrimaryDB SecondaryDB 请求数据操作 设置数据源类型 确认 执行操作(当选择主库时) 执行操作(当选择从库时) 返回结果 返回结果 返回响应 Client Service DataSourceRouter PrimaryDB SecondaryDB

七、多数据源事务管理

在多数据源环境下,事务管理变得更加复杂。可以使用JTA或分布式事务解决方案:

@Bean
public JtaTransactionManager transactionManager() {
    JtaTransactionManager transactionManager = new JtaTransactionManager();
    transactionManager.setUserTransaction(userTransaction());
    transactionManager.setTransactionManager(atomikosTransactionManager());
    return transactionManager;
}

@Bean(initMethod = "init", destroyMethod = "close")
public UserTransactionManager atomikosTransactionManager() {
    UserTransactionManager userTransactionManager = new UserTransactionManager();
    userTransactionManager.setForceShutdown(false);
    return userTransactionManager;
}

@Bean
public UserTransaction userTransaction() throws SystemException {
    UserTransactionImp userTransactionImp = new UserTransactionImp();
    userTransactionImp.setTransactionTimeout(300);
    return userTransactionImp;
}

八、最佳实践与注意事项

  1. 明确的包结构:为不同数据源的实体、仓库和服务划分明确的包路径
  2. 事务边界:清楚界定每个事务使用哪个数据源
  3. 性能考虑:避免在单个请求中频繁切换数据源
  4. 连接池配置:为每个数据源单独配置连接池参数
  5. 监控:实现多数据源的监控和健康检查

九、总结

Spring Boot提供了灵活的多数据源配置方式,无论是使用JPA还是MyBatis,都可以通过适当的配置实现多数据源访问。关键点在于:

  1. 正确配置多个DataSource bean
  2. 为每个数据源配置独立的事务管理器
  3. 明确划分不同数据源对应的仓库和实体类包路径
  4. 在复杂场景下考虑动态数据源路由或分布式事务

通过本文的介绍,您应该能够在Spring Boot项目中成功配置和使用多个数据源,满足各种复杂的业务需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值