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

Docker化MySQL依赖Web应用遇java.net.ConnectException连接拒绝问题

Docker Compose中Spring Boot应用无法连接MySQL容器,抛出Connection refused错误

我有一个依赖MySQL的Web应用,想把它Docker化来学习Docker并提升可分享性(他人无需手动搭建MySQL即可使用)。以下是我的操作步骤:

步骤1:编写Dockerfile

在项目根目录创建Dockerfile,内容如下:

FROM amazoncorretto:17-alpine-jdk

WORKDIR /app

COPY target/spring_bootstrap-0.0.1-SNAPSHOT.jar .

EXPOSE 8080

CMD ["java", "-jar", "spring_bootstrap-0.0.1-SNAPSHOT.jar"]

步骤2:编写docker-compose.yml

因需同时运行应用和MySQL组件,编写了如下docker-compose.yml:

version: '3'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    depends_on:
      - db
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://db:3307/users_db?useSSL=false&serverTimezone=UTC
      SPRING_DATASOURCE_USERNAME: pp_user
      SPRING_DATASOURCE_PASSWORD: pp_user

  db:
    image: mysql:latest
    ports:
      - "3307:3306"
    environment:
      MYSQL_DATABASE: users_db
      MYSQL_USER: pp_user
      MYSQL_PASSWORD: pp_user
      MYSQL_ROOT_PASSWORD: root_password

注:使用3307端口是因为3306被主机占用(外部未运行MySQL)。

步骤3:注释application.properties中的数据源配置

# connection properties
#spring.datasource.url=jdbc:mysql://localhost:3306/users_db?useSSL=false&serverTimezone=UTC
#spring.datasource.username=pp_user
#spring.datasource.password=pp_user

步骤4:执行clean和package生成最新jar包

步骤5:进入项目目录运行docker-compose up

执行后MySQL容器正常启动,但应用启动失败并退出,日志抛出如下错误:

bootstrap_fetch-app-1  | Caused by: java.net.ConnectException: Connection refused
bootstrap_fetch-app-1  |        at java.base/sun.nio.ch.Net.pollConnect(Native Method) ~[na:na]
bootstrap_fetch-app-1  |        at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) ~[na:na]
bootstrap_fetch-app-1  |        at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:547) ~[na:na]
bootstrap_fetch-app-1  |        at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:602) ~[na:na]
bootstrap_fetch-app-1  |        at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) ~[na:na]
bootstrap_fetch-app-1  |        at java.base/java.net.Socket.connect(Socket.java:633) ~[na:na]
bootstrap_fetch-app-1  |        at com.mysql.cj.protocol.StandardSocketFactory.connect(StandardSocketFactory.java:153) ~[mysql-connector-j-8.0.32.jar!/:8.0.32]
bootstrap_fetch-app-1  |        at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:63) ~[mysql-connector-j-8.0.32.jar!/:8.0.32]
bootstrap_fetch-app-1  |        ... 51 common frames omitted
bootstrap_fetch-app-1  |
bootstrap_fetch-app-1 exited with code 1

解决方案

你的问题主要出在两个地方:

1. JDBC URL中的端口配置错误

Docker Compose的服务之间通过内部网络通信时,使用的是容器自身暴露的端口,而不是映射到主机的端口。你的MySQL容器内部端口是3306(MySQL默认端口),3307:3306只是把主机的3307端口映射到容器的3306端口,供外部主机访问用的。

所以要修改app服务的SPRING_DATASOURCE_URL,把端口从3307改成3306:

SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/users_db?useSSL=false&serverTimezone=UTC

2. depends_on不保证MySQL服务就绪

depends_on: [db]仅仅保证app容器在db容器之后启动,但不保证MySQL服务已经完成初始化并可以接受连接。MySQL容器启动后,通常需要几秒到十几秒的时间完成数据库初始化、用户创建等操作,这时候Spring Boot应用已经尝试连接,就会抛出连接拒绝错误。

解决这个问题有几种常用方式:

方式一:在Docker Compose中配置健康检查

给db服务添加健康检查,让app等待MySQL健康检查通过后再启动:

services:
  app:
    # ... 其他配置
    depends_on:
      db:
        condition: service_healthy  # 等待db服务健康检查通过

  db:
    image: mysql:latest
    ports:
      - "3307:3306"
    environment:
      MYSQL_DATABASE: users_db
      MYSQL_USER: pp_user
      MYSQL_PASSWORD: pp_user
      MYSQL_ROOT_PASSWORD: root_password
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
      timeout: 20s
      retries: 10

方式二:在Spring Boot中配置连接重试

添加Spring Boot的重试依赖,并配置数据源的重试机制:

  1. 在pom.xml中添加依赖:
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. 在application.properties或环境变量中添加配置:
# 连接超时和重试配置
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.maximum-pool-size=10
# 启用重试
spring.retry.enabled=true
spring.datasource.hikari.initialization-fail-timeout=0  # 无限等待直到连接成功

方式三:使用等待脚本

在Dockerfile中添加wait-for-it.sh脚本,让应用启动前先等待MySQL端口就绪:

  1. 下载wait-for-it.sh到项目根目录,修改Dockerfile:
FROM amazoncorretto:17-alpine-jdk

WORKDIR /app

COPY wait-for-it.sh .
RUN chmod +x wait-for-it.sh

COPY target/spring_bootstrap-0.0.1-SNAPSHOT.jar .

EXPOSE 8080

CMD ["./wait-for-it.sh", "db:3306", "--", "java", "-jar", "spring_bootstrap-0.0.1-SNAPSHOT.jar"]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 07:59:54