无法连接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
相关产品推荐
相关产品推荐

