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

Spring Boot 3.1集成Testcontainers无法连接PostgreSQL求助

问题:Spring Boot Testcontainers 连接PostgreSQL失败

我编写了一个简单的测试用例用于验证数据库连接,但无法成功连接到数据库。

测试用例代码

@End2EndTest
@SpringBootTest(classes = [StartPostgresContainerExtensionTestsConfiguration::class])
@Testcontainers
class SpringBootPostgresTestcontainerTest(
    @Autowired private val abrechnungDbDataSource: DataSource?,
) {

    companion object {

        @Container
        @JvmStatic
        val postgresContainer = PostgreSQLContainer("postgres:13.8-bullseye").also { it.start() }

        @DynamicPropertySource
        @JvmStatic
        fun datasourceProperties(registry: DynamicPropertyRegistry) {
            registry.add("fonl.databases.abrechnung-db.name", postgresContainer::getDatabaseName)
            registry.add("fonl.databases.abrechnung-db.username", postgresContainer::getUsername)
            registry.add("fonl.databases.abrechnung-db.password", postgresContainer::getPassword)
            registry.add("fonl.databases.abrechnung-db.url", postgresContainer::getJdbcUrl)
        }
    }

    @Test
    fun `connection to database can be established`() {
        assertThat(abrechnungDbDataSource).isNotNull
        checkConnectivity(abrechnungDbDataSource!!)
    }

    private fun checkConnectivity(dataSource: DataSource) {
        dataSource.connection.isValid(3)
        val jdbcTemplate = JdbcTemplate(dataSource)
        val result = jdbcTemplate.queryForObject("SELECT 1", Int::class.java)
        check(result == 1)
    }
}

@Configuration
@EnableConfigurationProperties
class SpringBootPostgresTestcontainerTestConfiguration {

    private val log = LoggerFactory.getLogger(javaClass)

    @Bean
    @ConfigurationProperties("fonl.databases.abrechnung-db")
    fun abrechnungDbDataSourceProperties() = DataSourceProperties()

    @Bean
    fun abrechnungDbDataSource(abrechnungDbDataSourceProperties: DataSourceProperties): DataSource =
        abrechnungDbDataSourceProperties.also {
            logDataSourceProperties(it)
        }.initializeDataSourceBuilder().build()

    private fun logDataSourceProperties(dataSourceProperties: DataSourceProperties) {
        if (log.isDebugEnabled) {
            log.debug(
                "DriverClassname=${dataSourceProperties.driverClassName}; " +
                    "DataSourceName=${dataSourceProperties.name}; " +
                    "UserName=${dataSourceProperties.username}; " +
                    "Password=${dataSourceProperties.password}; " +
                    "url=${dataSourceProperties.url}"
            )
        }
    }
}

日志信息

09:36:15.892 [Test worker] INFO  tc.postgres:13.8-bullseye - Creating container for image: postgres:13.8-bullseye
09:36:15.903 [Test worker] INFO  tc.postgres:13.8-bullseye - Container postgres:13.8-bullseye is starting: 354a1f11fb796abd72af46d855d65849aac7d1e9cb41aa560941ec62b44ff82d
09:36:16.859 [Test worker] INFO  tc.postgres:13.8-bullseye - Container postgres:13.8-bullseye started in PT0.967635S
09:36:16.860 [Test worker] INFO  tc.postgres:13.8-bullseye - Container is started (JDBC URL: jdbc:postgresql://localhost:32771/test?loggerLevel=OFF)
09:36:16.867 [Test worker] INFO  d.a.f.m.t.p.SpringBootPostgresTestcontainerTest - Starting SpringBootPostgresTestcontainerTest using Java 17.0.6 with PID 7635 (started by alexander.rolfes in /Users/alexander.rolfes/sources/allianz/fonl-microlibraries/testing/test-support/test-support-postgres)
09:36:16.867 [Test worker] DEBUG d.a.f.m.t.p.SpringBootPostgresTestcontainerTest - Running with Spring Boot v3.1.6, Spring v6.0.14
09:36:16.867 [Test worker] INFO  d.a.f.m.t.p.SpringBootPostgresTestcontainerTest - The following 2 profiles are active: "test", "end2end-test"
09:36:17.477 [Test worker] DEBUG d.a.f.m.t.p.StartPostgresContainerExtensionTestsConfiguration$$SpringCGLIB$$0 - DriverClassname=org.postgresql.Driver; DataSourceName=test; UserName=test; Password=test; url=jdbc:postgresql://localhost:32771/test?loggerLevel=OFF
09:36:17.507 [Test worker] INFO  d.a.f.m.t.p.SpringBootPostgresTestcontainerTest - Started SpringBootPostgresTestcontainerTest in 4.295 seconds (process running for 5.297)
09:36:17.579 [Test worker] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
09:36:18.628 [Test worker] ERROR com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Exception during pool initialization.
org.postgresql.util.PSQLException: Connection to localhost:32771 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.

问题原因及解决方法

  • 手动启动容器导致时序异常
    你在初始化postgresContainer时手动调用了.also { it.start() },但Testcontainers框架会自动管理容器的生命周期(启动、健康检查、停止)。手动提前启动会导致Spring上下文初始化时,PostgreSQL服务可能还未完全就绪,或者端口映射未正确同步。

    解决:删除手动启动代码,让框架自动处理:

    @Container
    @JvmStatic
    val postgresContainer = PostgreSQLContainer("postgres:13.8-bullseye")
    
  • 容器健康检查未生效
    手动启动容器会跳过Testcontainers默认的健康检查逻辑,即使日志显示容器已启动,PostgreSQL内部服务可能还在初始化,此时尝试连接必然失败。依赖框架的自动启动逻辑,会等待容器的健康检查通过后再初始化Spring上下文。

  • Docker网络映射问题(可选排查)
    如果是Docker Desktop环境,偶尔会出现localhost映射异常,此时可以尝试使用postgresContainer.host替代localhost,不过getJdbcUrl()已经自动包含了正确的主机地址,所以只要删除手动启动代码,这个问题也会随之解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 08:24:59