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

将嵌入式MySQL替换为TestContainers:多数据源EntityManager适配问题

多数据源场景下TestContainers适配改造方案

核心思路

为两个数据源分别创建TestContainers MySQL容器实例,覆盖原有嵌入式数据库的DataSource配置,确保EntityManager配置类精准绑定对应容器的数据源,解决依赖注入错误问题。

步骤1:测试类中配置双容器与数据源Bean

在测试类中定义两个MySQL容器,并创建对应名称的DataSource Bean,替换原嵌入式DB的数据源配置:

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import javax.sql.DataSource;

@Testcontainers
@SpringBootTest
public class MultiDbIntegrationTest {

    // Request数据库容器
    @Container
    public static MySQLContainer<?> requestDbContainer = new MySQLContainer<>("mysql:8.0")
            .withDatabaseName("request_db")
            .withUsername("test_user")
            .withPassword("test_pass");

    // Catalog数据库容器
    @Container
    public static MySQLContainer<?> catalogDbContainer = new MySQLContainer<>("mysql:8.0")
            .withDatabaseName("catalog_db")
            .withUsername("test_user")
            .withPassword("test_pass");

    // 绑定Request数据源到对应的容器
    @Bean(name = "requestDataSource")
    public DataSource requestDataSource() {
        return DataSourceBuilder.create()
                .url(requestDbContainer.getJdbcUrl())
                .username(requestDbContainer.getUsername())
                .password(requestDbContainer.getPassword())
                .driverClassName(requestDbContainer.getDriverClassName())
                .build();
    }

    // 绑定Catalog数据源到对应的容器
    @Bean(name = "catalogDataSource")
    public DataSource catalogDataSource() {
        return DataSourceBuilder.create()
                .url(catalogDbContainer.getJdbcUrl())
                .username(catalogDbContainer.getUsername())
                .password(catalogDbContainer.getPassword())
                .driverClassName(catalogDbContainer.getDriverClassName())
                .build();
    }
}

步骤2:调整EntityManager配置类的数据源绑定

确保原有EntityManager配置类通过@Qualifier精准引用对应名称的DataSource Bean,避免依赖混淆:

RequestDBEntityManager配置

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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 javax.sql.DataSource;
import javax.persistence.EntityManagerFactory;

@Configuration
@EnableJpaRepositories(
        basePackages = "com.yourproject.request.repository",
        entityManagerFactoryRef = "requestEntityManagerFactory",
        transactionManagerRef = "requestTransactionManager"
)
public class RequestDBEntityManager {

    @Autowired
    @Qualifier("requestDataSource")
    private DataSource requestDataSource;

    @Bean(name = "requestEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean requestEntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(requestDataSource)
                .packages("com.yourproject.request.entity")
                .persistenceUnit("requestPU")
                .build();
    }

    @Bean(name = "requestTransactionManager")
    public PlatformTransactionManager requestTransactionManager(
            @Qualifier("requestEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

CatalogEntityManager配置

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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 javax.sql.DataSource;
import javax.persistence.EntityManagerFactory;

@Configuration
@EnableJpaRepositories(
        basePackages = "com.yourproject.catalog.repository",
        entityManagerFactoryRef = "catalogEntityManagerFactory",
        transactionManagerRef = "catalogTransactionManager"
)
public class CatalogEntityManager {

    @Autowired
    @Qualifier("catalogDataSource")
    private DataSource catalogDataSource;

    @Bean(name = "catalogEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean catalogEntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(catalogDataSource)
                .packages("com.yourproject.catalog.entity")
                .persistenceUnit("catalogPU")
                .build();
    }

    @Bean(name = "catalogTransactionManager")
    public PlatformTransactionManager catalogTransactionManager(
            @Qualifier("catalogEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

关键注意事项

  • Bean名称一致性:测试类中DataSource的Bean名称(如requestDataSource)必须和EntityManager配置类中@Qualifier指定的名称完全匹配,这是解决"找不到Bean"错误的核心。
  • 容器复用:用static修饰容器实例,可实现测试类间的容器复用,大幅提升测试执行效率。
  • 镜像版本匹配:使用与生产环境一致的MySQL镜像版本(如mysql:8.0),避免SQL语法或兼容性问题。
  • 连接池配置:若需添加连接池参数,可在测试类的DataSource构建中补充,或通过@ConfigurationProperties绑定配置文件中的属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 00:17:44