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

无法连接Testcontainers创建的PostgreSQL实例问题求助

解决Testcontainers PostgreSQL容器无法访问的问题

我来帮你排查下这个连接被拒绝的问题,主要是几个细节没处理对,咱们一步步解决:

1. 端口映射理解错误(核心问题)

你在代码里用了withExposedPorts(5555),这里存在两个误区:

  • PostgreSQL容器内部默认监听的是5432端口,你指定5555作为暴露的容器端口是错误的,容器里的Postgres根本没在这个端口上运行。
  • Testcontainers的withExposedPorts()是声明容器要对外暴露的内部端口,而不是直接绑定宿主机端口。默认情况下,Testcontainers会把容器内的端口随机映射到宿主机的一个可用端口,不会直接用你指定的5555。所以你直接用localhost:5555连接,自然会被拒绝——宿主机的这个端口根本没被容器占用。

2. 单例模式实现有问题

你的getCustomPostgresContainerInstance()方法里,当静态实例customPostgresContainer为空时,创建了新的容器实例但没有赋值给这个变量,导致每次调用这个方法都会生成新的容器对象,状态混乱,可能出现容器没正确启动的情况。

3. 重写stop()方法的隐患

你把stop()方法写成空实现,Testcontainers无法正确关闭和清理容器,长期运行会导致Docker里堆积大量无用容器,虽然不是当前连接问题的直接原因,但建议修正。


修正后的完整代码

public class CustomPostgresContainer extends PostgreSQLContainer<CustomPostgresContainer> {
    private static final String IMAGE_VERSION = "postgres:9.6";
    private static CustomPostgresContainer customPostgresContainer;
    
    // PostgreSQL容器内部默认端口,固定为5432
    private static final int POSTGRES_INTERNAL_PORT = 5432;
    private static final String DB_NAME = "ASIGDB_TEST";
    private static final String DB_USER= "test";
    private static final String DB_PASSWORD= "test";

    public CustomPostgresContainer() {
        super(IMAGE_VERSION);
    }

    public static CustomPostgresContainer getInstance() {
        if (customPostgresContainer == null) {
            // 创建实例后赋值给静态变量,保证单例
            customPostgresContainer = new CustomPostgresContainer()
                    .withDatabaseName(DB_NAME)
                    .withUsername(DB_USER)
                    .withPassword(DB_PASSWORD)
                    .withExposedPorts(POSTGRES_INTERNAL_PORT); // 暴露容器内的默认Postgres端口
        }
        return customPostgresContainer;
    }

    // 不需要重写start方法,super.start()已经能正确启动容器
    // @Override
    // public void start() {
    //     super.start();
    // }

    @Override
    public void stop() {
        // 让Testcontainers正常清理容器,不要空实现
        super.stop();
    }
}

正确的使用方式

当你需要连接数据库时,按以下步骤获取正确的连接信息:

// 获取单例容器并启动
CustomPostgresContainer postgresContainer = CustomPostgresContainer.getInstance();
postgresContainer.start();

// 方式一:直接用Testcontainers提供的JDBC URL(推荐)
String jdbcUrl = postgresContainer.getJdbcUrl();
// 这个URL已经包含了正确的宿主机地址、映射端口、数据库名,比如:
// jdbc:postgresql://localhost:32768/ASIGDB_TEST?user=test&password=test

// 方式二:手动获取宿主机映射端口
int hostPort = postgresContainer.getMappedPort(CustomPostgresContainer.POSTGRES_INTERNAL_PORT);
// 此时连接地址为 localhost:hostPort,用户名test,密码test,数据库ASIGDB_TEST

额外注意事项

  • 如果一定要固定宿主机端口(不推荐,易冲突),可以用withFixedExposedPort(宿主机端口, 容器内部端口),比如:
    .withFixedExposedPort(5555, POSTGRES_INTERNAL_PORT)
    
    这样宿主机的5555端口会映射到容器内的5432,此时你才能用localhost:5555连接。
  • 用DBeaver连接时,要确保填入的端口是映射后的宿主机端口(可以通过docker ps命令查看容器的端口映射信息,比如0.0.0.0:32768->5432/tcp里的32768就是宿主机端口)。
  • 检查Docker是否正常运行,用docker ps确认容器处于Up状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:11:03