Spring Boot 3.3.4配置双数据源报错:存在两个JdbcMappingContext Bean
Spring Boot 3.3+(Spring 6.1+)双数据源无JPA配置方案
问题原因
Spring Data JDBC在6.1版本(对应Spring Boot 3.3+)中调整了自动配置逻辑:当存在多个数据源时,默认自动配置会导致JdbcMappingContext Bean冲突——框架无法自动区分多个数据源对应的映射上下文,因此抛出"expected single matching bean but found 2"异常。旧版本(如Spring Boot 3.1.x)的自动配置逻辑允许隐式为每个数据源创建独立上下文,但新版本需要显式绑定组件关系。
解决方案
1. 排除自动配置类
在启动类上排除Spring Data JDBC的自动配置,避免默认创建全局的JdbcMappingContext:
@SpringBootApplication(exclude = {SpringDataJdbcAutoConfiguration.class, JdbcDataAutoConfiguration.class}) public class MultiDataSourceApplication { public static void main(String[] args) { SpringApplication.run(MultiDataSourceApplication.class, args); } }
2. 为每个数据源创建独立配置类
为每个数据源编写专属配置类,显式声明所有关联组件(数据源、事务管理器、Jdbc模板、映射上下文等),并通过@EnableJdbcRepositories绑定到对应包下的Repository。
第一个数据源配置示例
@Configuration @EnableJdbcRepositories( basePackages = "com.yourproject.repository.db1", // 该数据源对应的Repository所在包 jdbcOperationsRef = "db1JdbcTemplate", transactionManagerRef = "db1TransactionManager", mappingContextRef = "db1JdbcMappingContext" // 绑定专属映射上下文 ) public class Db1DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.db1") // 对应配置文件中的前缀 public DataSource db1DataSource() { return DataSourceBuilder.create().build(); } @Bean public PlatformTransactionManager db1TransactionManager() { return new DataSourceTransactionManager(db1DataSource()); } @Bean public JdbcTemplate db1JdbcTemplate() { return new JdbcTemplate(db1DataSource()); } @Bean public NamedParameterJdbcTemplate db1NamedJdbcTemplate() { return new NamedParameterJdbcTemplate(db1DataSource()); } @Bean public JdbcMappingContext db1JdbcMappingContext(Optional<NamingStrategy> namingStrategy) { JdbcMappingContext context = new JdbcMappingContext(namingStrategy.orElse(NamingStrategy.INSTANCE)); context.setSimpleTypeHolder(SimpleTypeHolder.DEFAULT); return context; } @Bean public JdbcConverter db1JdbcConverter(JdbcMappingContext db1JdbcMappingContext) { DefaultJdbcConverter converter = new DefaultJdbcConverter(db1JdbcMappingContext, DefaultIdentifierProcessing.INSTANCE); converter.setDataAccessStrategy(new DefaultDataAccessStrategy( db1JdbcMappingContext, converter, db1NamedJdbcTemplate() )); return converter; } }
第二个数据源配置示例
复制上述配置,将所有db1前缀替换为db2,修改basePackages为对应Repository的包路径,配置文件前缀改为spring.datasource.db2即可。
3. 配置文件示例
在application.yml中配置两个数据源:
spring: datasource: db1: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db1 username: root password: password db2: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db2 username: root password: password
4. Repository编写
将不同数据源的Repository分别放在对应包下,例如:
// db1的Repository package com.yourproject.repository.db1; import org.springframework.data.jdbc.repository.query.Query; import org.springframework.data.repository.CrudRepository; import com.yourproject.model.db1.User; public interface UserRepository extends CrudRepository<User, Long> { @Query("SELECT * FROM users WHERE age > :age") List<User> findByAgeGreaterThan(int age); }
关键注意点
- 每个数据源的所有组件(
JdbcMappingContext、JdbcConverter、事务管理器等)必须有唯一的Bean名称,避免冲突。 @EnableJdbcRepositories中的mappingContextRef是核心,必须指定对应数据源的JdbcMappingContextBean,确保Repository使用正确的映射上下文。- 若需要直接使用
JdbcTemplate,需通过@Qualifier注入对应实例:
@Autowired @Qualifier("db1JdbcTemplate") private JdbcTemplate db1JdbcTemplate;
内容的提问来源于stack exchange,提问作者jpprade
相关产品推荐
相关产品推荐

