因为容器内localhost指向自身而非宿主机,需改用host.docker.internal(宿主机)或服务名(同网络MySQL容器);同时须配置MySQL允许远程访问、检查防火墙,并避免仅依赖depends_on控制启动顺序。

数据库连接字符串里 localhost 为什么在容器里连不上?
因为容器内的 localhost 指的是它自己,不是宿主机,更不是另一个 MySQL 容器。你看到的错误通常是 dial tcp 127.0.0.1:3306: connect: connection refused。
- 开发时本地直连用
localhost没问题,但放进 Docker 后必须改成服务名(如mysql),这个名称来自docker-compose.yml中定义的 service 名称 - 如果用单个
docker run启动,得用--network让 Go 容器和 MySQL 容器在同一个自定义网络里,并用容器名通信 -
tcp(localhost)这种写法在容器里永远错,哪怕你把 MySQL 也塞进同一个容器——GORM 默认不走 Unix socket,仍会尝试 TCP 连接
parseTime=true 和 loc=Local 必须同时配吗?
不是必须,但强烈建议配 parseTime=true;而 loc=Local 在容器化场景下反而容易出问题。
-
parseTime=true是刚需:没有它,MySQL 返回的DATETIME字段会被 GORM 当成字符串,time.Time字段读出来是零值 -
loc=Local表示让 Go 用容器当前系统时区解析时间,但如果容器没设时区(比如用scratch镜像),loc=Local会退化为 UTC,导致时间错 8 小时 - 更稳妥的做法是显式指定:
loc=Asia%2FShanghai(URL 编码后),或直接用loc=UTC+ 业务层转换,避免依赖容器环境
Docker Compose 里 MySQL 和 Go 应用怎么设置启动顺序?
不能只靠 depends_on,它只控制容器启动顺序,不等 MySQL 服务真正就绪。
-
depends_on只是让 Go 容器在 MySQL 容器 start 之后才 start,但 MySQL 可能还在初始化、建库、加载数据,此时 GORM 连接仍会失败 - 推荐加健康检查 + 初始化等待逻辑:MySQL service 加
healthcheck,Go 侧在init()或 main 入口里用循环重试gorm.Open,配合time.Sleep和超时退出 - 简单方案:在 Go 启动脚本里加
until nc -z mysql 3306; do sleep 2; done(需镜像含netcat),但不如代码内重试可控
GORM 连接池参数在容器里要调小吗?
要,而且必须调,否则多 Pod 下容易打爆数据库连接数。
- 默认
MaxOpenConns=0(不限制),一个 Pod 开几百连接很常见;K8s 里 5 个副本就是上千连接,MySQL 很快报Too many connections - 典型配置:
DB.SetMaxOpenConns(10)、DB.SetMaxIdleConns(5)、DB.SetConnMaxLifetime(time.Hour) - 注意:这些是运行时设置,不是
gorm.Config初始化时的选项,得在gorm.Open返回*gorm.DB后立刻调用 - 如果用了连接池中间件(如 pgxpool),GORM 不再管理底层连接,得单独配中间件的池参数
init() 或 main 里对 gorm.Open 的 error 做 fatal 处理,并确保日志能输出到 stdout。


















