You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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是核心,必须指定对应数据源的JdbcMappingContext Bean,确保Repository使用正确的映射上下文。
  • 若需要直接使用JdbcTemplate,需通过@Qualifier注入对应实例:
@Autowired
@Qualifier("db1JdbcTemplate")
private JdbcTemplate db1JdbcTemplate;

内容的提问来源于stack exchange,提问作者jpprade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 10:13:16