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

Docker Compose部署.NET API+MySQL+EF时插入数据失败求助

问题排查:Docker Compose部署.NET API + MySQL时EF插入失败

问题描述

我用Docker Compose部署基于.NET的API服务,搭配MySQL数据库,通过API端触发Entity Framework(EF)的数据库迁移操作。API和MySQL容器看起来都正常启动了,但发起请求时,Docker控制台报出EF执行插入命令失败的错误:

mysql-1  | 2024-10-30T03:02:44.680273Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.40'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.                                                 
api-1    | fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
api-1    |       Failed executing DbCommand (44ms) [Parameters=[@p0='?' (DbType = Int32), @p1='?' (Size = 4000), @p2='?' (Size = 4000), @p3='?' (Size = 4000)], CommandType='Text', CommandTimeout='30']                                                            
api-1    |       SET AUTOCOMMIT = 1;
api-1    |       INSERT INTO `User` (`Id`, `Email`, `Name`, `Password`)                                                           
api-1    |       VALUES (@p0, @p1, @p2, @p3); 

相关配置文件

Dockerfile

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["ApiNetEFMySQL.csproj", "."]
RUN dotnet restore "./ApiNetEFMySQL.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./ApiNetEFMySQL.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./ApiNetEFMySQL.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ApiNetEFMySQL.dll"]

docker-compose.yml(含EF命令配置)

services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
      - ConnectionStrings__LocalConnection=Server=mysql;Port=3306;Database=testapi;User ID=root;Password=2870FJlw;
    depends_on:
      - mysql
    command: >
      sh -c "until nc -z mysql 3306; do echo 'Waiting for MySQL...'; sleep 2; done; dotnet ef database update; dotnet ApiNetEFMySQL.dll"
    networks:
      - my_network

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: 2870FJlw
      MYSQL_DATABASE: testapi
    ports:
      - "3307:3306"
    volumes:
      - mysql_data:/var/lib/mysql
    networks:
      - my_network

volumes:
  mysql_data:

networks:
  my_network:

连接字符串配置

"ConnectionStrings": {
    "LocalConnection": "Server=mysql;Port=3307;Database=testapi;User ID=root;Password=<mypassword>;"
  }
}

Program.cs数据库配置

var connection = builder.Configuration.GetConnectionString("LocalConnection") ??
        throw new InvalidOperationException("String de conexion no encontrada.");
builder.Services.AddDbContext<UserContext>(options =>
    options.UseMySql(
        connection,
        ServerVersion.AutoDetect(connection)));

排查与解决方案

1. 修复连接字符串端口错误

容器内部通过Docker网络访问MySQL时,必须使用容器内部端口3306,而非宿主机映射的3307端口。当前本地配置文件中的连接字符串端口写反了,导致API无法正确连接数据库。

修正后的连接字符串:

"ConnectionStrings": {
  "LocalConnection": "Server=mysql;Port=3306;Database=testapi;User ID=root;Password=2870FJlw;"
}

2. 解决EF迁移无法执行的问题

当前Dockerfile最终使用的是aspnet:8.0运行时镜像,该镜像不包含.NET SDK和EF工具,因此docker-compose中配置的dotnet ef database update命令会执行失败,导致数据库表未创建,插入操作自然报错。

推荐两种解决方式:

方案A:程序启动时自动执行迁移(推荐)

在Program.cs中添加自动迁移逻辑,替代容器启动时的EF命令:

var app = builder.Build();

// 自动执行数据库迁移(生产环境需谨慎使用,建议提前手动执行)
using (var scope = app.Services.CreateScope())
{
    var dbContext = scope.ServiceProvider.GetRequiredService<UserContext>();
    dbContext.Database.Migrate();
}

// 后续中间件配置...
app.Run();

同时删除docker-compose.yml中command字段里的dotnet ef database update;部分,保留等待MySQL的逻辑即可:

command: >
  sh -c "until nc -z mysql 3306; do echo 'Waiting for MySQL...'; sleep 2; done; dotnet ApiNetEFMySQL.dll"

方案B:给容器安装EF工具(不推荐,镜像体积增大)

修改Dockerfile的final阶段,安装EF工具:

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
# 安装EF全局工具
RUN dotnet tool install --global dotnet-ef
ENV PATH="$PATH:/home/app/.dotnet/tools"
ENTRYPOINT ["dotnet", "ApiNetEFMySQL.dll"]

3. 验证数据库表是否存在

进入MySQL容器,检查testapi数据库中是否存在User表:

# 进入MySQL容器
docker exec -it mysql-1 mysql -uroot -p2870FJlw
# 切换到testapi数据库
use testapi;
# 查看所有表
show tables;

如果没有User表,说明迁移未执行成功,回到步骤2排查。

4. 确认MySQL用户权限

检查root用户是否允许从Docker网络连接:
在MySQL命令行中执行:

SELECT user, host FROM mysql.user WHERE user='root';

若host字段为%,则表示允许所有主机连接,权限正常;若不是,需修改权限:

ALTER USER 'root'@'%' IDENTIFIED BY '2870FJlw';
FLUSH PRIVILEGES;

内容的提问来源于stack exchange,提问作者Fede Woodward

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:07:04