配置多数据源需为每个数据源独立定义连接属性、数据源实例、实体管理器工厂和事务管理器,通过@Primary标注主数据源,@EnableJpaRepositories指定各自包路径实现隔离,确保事务管理器与数据源一一对应,并在@Service中用@Transactional("xxxTransactionManager")显式指定事务管理器以保障事务独立性。

在Spring Boot应用中配置多数据源,核心在于为每个数据源独立定义其连接属性、数据源实例、JPA实体管理器工厂以及事务管理器。这通常通过创建多个配置类来实现,每个类负责一个数据源的完整生命周期管理,并确保实体和仓库(Repository)能正确地与各自的数据源关联起来。这能让一个应用同时处理来自不同数据库的数据,例如,一个用于核心业务,另一个用于历史数据或报表。
要在Spring Boot应用中配置多个MySQL数据源,我们需要以下几个步骤。这不仅仅是把配置堆在一起,更重要的是理清各个组件之间的依赖和隔离。
首先,确保你的
pom.xml
spring-boot-starter-data-jpa
mysql-connector-java
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>接着,在
application.properties
application.yml
primary
secondary
# Primary DataSource Configuration spring.datasource.primary.url=jdbc:mysql://localhost:3306/primary_db?useSSL=false&serverTimezone=UTC spring.datasource.primary.username=root spring.datasource.primary.password=password spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.primary.hikari.maximum-pool-size=10 spring.datasource.primary.hikari.minimum-idle=5 # Secondary DataSource Configuration spring.datasource.secondary.url=jdbc:mysql://localhost:3306/secondary_db?useSSL=false&serverTimezone=UTC spring.datasource.secondary.username=root spring.datasource.secondary.password=password spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.secondary.hikari.maximum-pool-size=10 spring.datasource.secondary.hikari.minimum-idle=5 # JPA properties for Primary spring.jpa.primary.database-platform=org.hibernate.dialect.MySQL8Dialect spring.jpa.primary.hibernate.ddl-auto=update spring.jpa.primary.show-sql=true # JPA properties for Secondary spring.jpa.secondary.database-platform=org.hibernate.dialect.MySQL8Dialect spring.jpa.secondary.hibernate.ddl-auto=update spring.jpa.secondary.show-sql=true
然后,我们需要创建两个独立的配置类,分别管理
primary
secondary
PrimaryDataSourceConfig.java:
package com.example.multids.config;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    entityManagerFactoryRef = "primaryEntityManagerFactory",
    transactionManagerRef = "primaryTransactionManager",
    basePackages = {"com.example.multids.primary.repository"} // 确保扫描Primary数据源的Repository
)
public class PrimaryDataSourceConfig {
    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource.primary")
    public DataSourceProperties primaryDataSourceProperties() {
        return new DataSourceProperties();
    }
    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource.primary.hikari")
    public DataSource primaryDataSource(@Qualifier("primaryDataSourceProperties") DataSourceProperties properties) {
        return primaryDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }
    @Bean(name = "primaryEntityManagerFactory")
    @Primary
    public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
            EntityManagerFactoryBuilder builder, @Qualifier("primaryDataSource") DataSource dataSource) {
        Map<String, String> jpaProperties = new HashMap<>();
        jpaProperties.put("hibernate.hbm2ddl.auto", "update");
        jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
        jpaProperties.put("hibernate.show_sql", "true"); // 方便调试
        return builder
                .dataSource(dataSource)
                .properties(jpaProperties)
                .packages("com.example.multids.primary.entity") // 确保扫描Primary数据源的实体
                .persistenceUnit("primaryPersistenceUnit")
                .build();
    }
    @Bean(name = "primaryTransactionManager")
    @Primary
    public PlatformTransactionManager primaryTransactionManager(
            @Qualifier("primaryEntityManagerFactory") LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory) {
        return new JpaTransactionManager(primaryEntityManagerFactory.getObject());
    }
}SecondaryDataSourceConfig.java:
package com.example.multids.config;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    entityManagerFactoryRef = "secondaryEntityManagerFactory",
    transactionManagerRef = "secondaryTransactionManager",
    basePackages = {"com.example.multids.secondary.repository"} // 确保扫描Secondary数据源的Repository
)
public class SecondaryDataSourceConfig {
    @Bean
    @ConfigurationProperties("spring.datasource.secondary")
    public DataSourceProperties secondaryDataSourceProperties() {
        return new DataSourceProperties();
    }
    @Bean
    @ConfigurationProperties("spring.datasource.secondary.hikari")
    public DataSource secondaryDataSource(@Qualifier("secondaryDataSourceProperties") DataSourceProperties properties) {
        return secondaryDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }
    @Bean(name = "secondaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
            EntityManagerFactoryBuilder builder, @Qualifier("secondaryDataSource") DataSource dataSource) {
        Map<String, String> jpaProperties = new HashMap<>();
        jpaProperties.put("hibernate.hbm2ddl.auto", "update");
        jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
        jpaProperties.put("hibernate.show_sql", "true");
        return builder
                .dataSource(dataSource)
                .properties(jpaProperties)
                .packages("com.example.multids.secondary.entity") // 确保扫描Secondary数据源的实体
                .persistenceUnit("secondaryPersistenceUnit")
                .build();
    }
    @Bean(name = "secondaryTransactionManager")
    public PlatformTransactionManager secondaryTransactionManager(
            @Qualifier("secondaryEntityManagerFactory") LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory) {
        return new JpaTransactionManager(secondaryEntityManagerFactory.getObject());
    }
}关键点:
DataSourceProperties
@ConfigurationProperties
@Primary
DataSource
EntityManagerFactory
@Qualifier
@EnableJpaRepositories
entityManagerFactoryRef
transactionManagerRef
basePackages
LocalContainerEntityManagerFactoryBean
EntityManagerFactory
JpaTransactionManager
EntityManagerFactory
最后,确保你的实体和Repository分别放在对应的包下,例如:
com.example.multids.primary.entity
com.example.multids.primary.repository
com.example.multids.secondary.entity
com.example.multids.secondary.repository
这样,当你在服务层使用Repository时,Spring就能根据配置正确地路由到对应的数据源。
这事儿吧,说起来也挺常见的。你可能一开始没想过,但项目一复杂,各种历史包袱、业务隔离、性能考量就都冒出来了。配置多个数据源,通常不是为了“炫技”,而是为了解决实际问题。
我个人觉得,最常见的场景就是遗留系统集成。你想啊,一个新项目用Spring Boot开发,但很多老数据还在一个老旧的数据库里,你又不能一下把所有数据都迁移过来,或者说,迁移的成本和风险太高。这时候,配置一个额外的数据源去读写老数据库,就成了最稳妥的方案。
再来就是业务隔离和数据安全。有些时候,不同业务模块的数据,在逻辑上就应该分开,甚至可能因为合规性要求,需要物理隔离。比如,用户敏感信息可能放在一个高安全级别的数据库里,而一些公开的商品信息则放在另一个数据库。这样即使一个数据库出了问题,也不会影响到所有数据。
还有就是性能优化和分库分表。虽然Spring Boot本身不直接提供分库分表的能力,但多数据源是实现这些高级策略的基础。当你的数据量大到单个数据库无法承受时,你可能会把数据分散到多个数据库中,这时候你的应用就需要同时连接并管理这些分散的数据源。或者,你可能有一个高并发写入的业务,需要一个专门的数据库,而另一个数据库则用于低频的报表查询,它们对数据库的配置和优化方向是完全不同的。
总的来说,多数据源的配置,往往是业务发展到一定阶段,对数据管理和系统架构提出更高要求时的必然选择。它不是为了让系统变得更复杂,而是为了让系统在面对复杂需求时,能保持灵活性和健壮性。
我跟你说,这玩意儿配置起来,看似一套流程,但真要跑起来,各种稀奇古怪的问题就来了。我之前就遇到过好几次,搞得我焦头烂额。
首先,事务管理是最大的一个“坑”。Spring的
@Transactional
@Transactional
@Transactional("secondaryTransactionManager")其次,实体和仓库的扫描范围。
@EnableJpaRepositories
@EntityScan
LocalContainerEntityManagerFactoryBean
packagesToScan
basePackages
EntityManagerFactory
再者,Spring Boot的自动配置干扰。Spring Boot非常“聪明”,它会尝试自动配置一个数据源。当我们手动配置多个数据源时,就可能和它的自动配置发生冲突。通常,通过明确定义所有必要的Bean并使用
@Primary
DataSourceAutoConfiguration
还有,连接池的独立配置。每个数据源都会有自己的连接池(比如HikariCP)。你需要在
application.properties
最后,一个比较隐蔽的“坑”是,如果你在某个服务方法里,不小心混用了来自不同数据源的Repository,并且没有正确管理事务,那么就很容易出现问题。我建议,尽量让处理某个特定数据源的业务逻辑,集中在它自己的服务层中,避免在同一个方法里跨数据源进行复杂操作,除非你真的清楚自己在做什么,并且已经为之设计了完善的事务策略。
事务这块,是多数据源配置里最容易出岔子,也最关键的地方。搞不好,数据一致性就没了。要确保不同数据源的事务独立且正确地工作,核心在于显式指定和隔离。
首先,每个数据源必须拥有自己独立的事务管理器。这是基础中的基础。在我们的配置中,我们为
primary
primaryTransactionManager
secondary
secondaryTransactionManager
EntityManagerFactory
其次,也是最关键的一步,就是在你的业务逻辑层,也就是通常的Service层方法上,使用
@Transactional
比如,如果你有一个操作
primary
@Service
public class PrimaryService {
    // ... 注入 PrimaryRepository
    @Transactional("primaryTransactionManager") // 明确指定使用Primary数据源的事务管理器
    public void performPrimaryDbOperation(PrimaryEntity entity) {
        // ... 对Primary数据源的操作
    }
}而对于操作
secondary
@Service
public class SecondaryService {
    // ... 注入 SecondaryRepository
    @Transactional("secondaryTransactionManager") // 明确指定使用Secondary数据源的事务管理器
    public void performSecondaryDbOperation(SecondaryEntity entity) {
        // ... 对Secondary数据源的操作
    }
}这样,当
performPrimaryDbOperation
primaryTransactionManager
primary_db
performSecondaryDbOperation
secondary_db
这里需要特别强调的是,除非你引入了像JTA(Java Transaction API)这样的分布式事务管理器,否则Spring的@Transactional
所以,我的建议是,尽量保持业务逻辑的清晰和单一职责。一个服务方法,最好只专注于操作一个数据源。如果确实需要协调多个数据源的操作,你可能需要更高层级的业务逻辑来编排这些独立事务,并在应用层面处理可能出现的补偿逻辑,而不是依赖一个“神奇”的分布式事务来解决所有问题。
以上就是在Spring Boot应用中配置多数据源(Multiple MySQL DataSources)的详细内容,更多请关注php中文网其它相关文章!
 
                        
                        每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
 
                 
                                
                                 收藏
收藏
                                                                             
                                
                                 收藏
收藏
                                                                             
                                
                                 收藏
收藏
                                                                            Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号