mysql容器启动后java连不上,主因是java应用启动快于mysql初始化完成;需配置healthcheck、wait-for-it.sh等待及连接串显式声明时区和字符集。

MySQL容器启动后Java连不上:检查网络和连接字符串
Java应用启动快于MySQL初始化完成,这是最常见“Connection refused”错误的根源。Docker Compose默认不等待依赖容器就绪,depends_on只控制启动顺序,不校验服务可用性。
- 在Java端加重试逻辑,比如用
spring-boot-starter-jdbc时配置spring.datasource.hikari.connection-timeout=30000并配合spring.datasource.hikari.initialization-fail-timeout=-1 - MySQL服务名必须和
services下的key一致,Java里写jdbc:mysql://mysql:3306/mydb,不能写localhost或127.0.0.1 - 确认MySQL镜像启用了远程访问:官方镜像默认允许
root从任意host连接,但若自定义my.cnf,需确保有bind-address = 0.0.0.0
docker-compose.yml里MySQL的healthcheck怎么写才有效
光靠depends_on不够,必须配healthcheck让Docker知道MySQL真正“活了”,否则Java容器可能在MySQL还在初始化时就尝试建连。
- 用
mysqladmin ping比nc -z mysql 3306更可靠,后者端口通了但MySQL进程未必能响应SQL - 示例片段:
healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"] timeout: 20s retries: 10 start_period: 40s
-
start_period要足够长(至少40s),因为MySQL首次启动会初始化数据目录,耗时远超普通服务
Java容器如何等MySQL健康后再启动
Compose本身不提供“等待健康服务”的原生语法,得靠工具链补位。硬等sleep 30不可靠,也违背容器设计原则。
- 推荐在Java应用启动脚本里用
wait-for-it.sh:下载脚本后,在command中写./wait-for-it.sh mysql:3306 -- java -jar app.jar - 如果用Spring Boot 2.3+,可启用
spring.sql.init.mode=always配合spring.sql.init.continue-on-error=true,让建表失败不中断启动 - 避免在
Dockerfile里用RUN执行数据库初始化——那发生在镜像构建阶段,不是容器运行时
时区、字符集不一致导致Java读写乱码
MySQL容器默认时区是UTC,Java应用常跑在本地时区;默认字符集是latin1,而Java项目普遍用utf8mb4。这两处不统一,插入中文就变???,时间字段偏移8小时。
立即学习“Java免费学习笔记(深入)”;
- MySQL服务配置加环境变量:
MYSQL_TIME_ZONE: "+08:00"和MYSQL_COLLATION: utf8mb4_unicode_ci - Java连接串必须显式声明:
jdbc:mysql://mysql:3306/mydb?serverTimezone=GMT%2B8&characterEncoding=utf8mb4&useUnicode=true - 验证是否生效:进MySQL容器执行
mysql -uroot -p -e "SHOW VARIABLES LIKE 'character_set%'; SHOW VARIABLES LIKE 'time_zone';"
实际部署时最容易被忽略的是MySQL首次启动的start_period和Java连接串里serverTimezone的URL编码——漏掉%2B写成GMT+8,驱动会解析失败,报错信息里根本不会提时区,只会说“Unable to find a valid timezone”。










