将 PostgreSQL 数据库连接到 Spring 应用程序均在 docker 中运行连接被拒绝

问题描述

我一直在尝试在我的 Spring 应用程序和 Postgresql 数据库之间建立连接。数据库和应用程序都在 docker 容器中启动。关键是当执行 docker-compose up 时,控制台日志表明到 localhost:5432 的连接已被拒绝。我设法通过python成功连接到数据库,但我无法在java中建立连接,因此我添加了用于建立连接的每个文件内容。我和我的团队将非常感谢即使是很小的帮助!

medical-clinic | org.postgresql.util.PsqlException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
medical-clinic |        at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:303) ~[postgresql-42.2.18.jar!/:42.2.18]
medical-clinic |        at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:51) ~[postgresql-42.2.18.jar!/:42.2.18]
medical-clinic |        at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:225) ~[postgresql-42.2.18.jar!/:42.2.18]
medical-clinic |        at org.postgresql.Driver.makeConnection(Driver.java:465) ~[postgresql-42.2.18.jar!/:42.2.18]
medical-clinic |        at org.postgresql.Driver.connect(Driver.java:264) ~[postgresql-42.2.18.jar!/:42.2.18]
medical-clinic |        at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) ~[HikariCP-3.4.5.jar!/:na]
medical-clinic |        at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:358) ~[HikariCP-3.4.5.jar!/:na]
medical-clinic |        at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:206) ~[HikariCP-3.4.5.jar!/:na]
medical-clinic |        at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:477) ~[HikariCP-3.4.5.jar!/:na]
medical-clinic |        at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:560) ~[HikariCP-3.4.5.jar!/:na]
medical-clinic |        at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:115) ~[HikariCP-3.4.5.jar!/:na]
medical-clinic |        at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) ~[HikariCP-3.4.5.jar!/:na]
medical-clinic |        at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentinitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentinitiator.java:180) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentinitiator.initiateService(JdbcEnvironmentinitiator.java:68) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentinitiator.initiateService(JdbcEnvironmentinitiator.java:35) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:101) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.java:286) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:243) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:176) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:118) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.Metadata(EntityManagerFactoryBuilderImpl.java:1224) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1255) ~[hibernate-core-5.4.21.Final.jar!/:5.4.21.Final]
medical-clinic |        at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) ~[spring-orm-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
medical-clinic |        at org.springframework.orm.jpa.LocalContainerEntityManagerfactorybean.createNativeEntityManagerFactory(LocalContainerEntityManagerfactorybean.java:365) ~[spring-orm-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
medical-clinic |        at org.springframework.orm.jpa.AbstractEntityManagerfactorybean.buildNativeEntityManagerFactory(AbstractEntityManagerfactorybean.java:391) ~[spring-orm-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
medical-clinic |        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
medical-clinic |        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
medical-clinic |        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
medical-clinic |        at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
medical-clinic | Caused by: java.net.ConnectException: Connection refused (Connection refused)
medical-clinic |        at java.base/java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:na]
medical-clinic |        at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399) ~[na:na]
medical-clinic |        at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242) ~[na:na]
medical-clinic |        at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224) ~[na:na]
medical-clinic |        at java.base/java.net.socksSocketImpl.connect(SocksSocketImpl.java:403) ~[na:na]
medical-clinic |        at java.base/java.net.socket.connect(Socket.java:609) ~[na:na]
medical-clinic |        at org.postgresql.core.PGStream.createSocket(PGStream.java:231) ~[postgresql-42.2.18.jar!/:42.2.18]
medical-clinic |        at org.postgresql.core.PGStream.<init>(PGStream.java:95) ~[postgresql-42.2.18.jar!/:42.2.18]
medical-clinic |        at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:98) ~[postgresql-42.2.18.jar!/:42.2.18]
medical-clinic |        at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:213) ~[postgresql-42.2.18.jar!/:42.2.18]
medical-clinic |        ... 34 common frames omitted

这是我的 docker-compose.yml 文件

version: '3'

services:
  db:
    image: 'postgres:13.1-alpine'
    container_name: db
    environment:
      - POSTGRES_DB=MedClinic
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=123
      
      - ALLOW_IP_RANGE-0.0.0.0/0
    volumes:
      - ./src/main/resources/db/init.sql:/docker-entrypoint-initdb.d/1-schema.sql
      - ./src/main/resources/db/data.sql:/docker-entrypoint-initdb.d/2-data.sql
    ports:
      - "5432:5432"
  app:
    image: 'medical-clinic:latest'
    build:
      context: .
    container_name: 'medical-clinic'
    ports:
      - 8080:8080
    environment:
      - SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/MedClinic
      - SPRING_DATASOURCE_USERNAME=postgres
      - SPRING_DATASOURCE_PASSWORD=123
      - SPRING_JPA_HIBERNATE_DDL_AUTO=update
    depends_on:
      - db

pom.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.company</groupId>
    <artifactId>medical-clinic</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>medical-clinic</name>
    <description>Medical clinic app</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.2.18</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

和 application.properties

spring.datasource.url=jdbc:postgresql://localhost:5432/MedClinic
spring.datasource.username=postgres
spring.datasource.password=123
spring.datasource.driver-class-name=org.postgresql.Driver
# Keep the connection alive if idle for a long time (needed in production)
spring.datasource.testWhileIdle=true
spring.datasource.validationQuery=SELECT 1
# ===============================
# = JPA / HIBERNATE
# ===============================
# Show or not log for each sql query
spring.jpa.show-sql=true
# Hibernate ddl auto (create,create-drop,update): with "create-drop" the database
# schema will be automatically created afresh for every start of application
spring.jpa.hibernate.ddl-auto=create-drop

# Naming strategy
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy

# Allows Hibernate to generate sql optimized for a particular DBMS
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgresqlDialect

解决方法

您可能只是遇到了一个简单的计时问题。在 docker-compose.yaml 中使用 db 依赖项可设置网络可见性。但是:Docker Compose 无法知道您的 Postgres 容器何时准备好接受连接。您的应用程序可能只是尝试尽早访问 Postgres?查看官方手册,他们实际上基于 Postgres 的示例:https://docs.docker.com/compose/startup-order/