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

Docker环境下EF Core替换SQLite文件后无法获取新值的问题

问题背景

运行环境

  • .NET 6
  • Microsoft.EntityFrameworkCore.Sqlite: 6.0.9
  • Docker Desktop: 20.10.16
  • OS: Win10

场景与代码

我创建了一个ASP.NET Core项目,通过API查询SQLite数据库,核心接口代码如下:

[ApiController]
[Route("[controller]")]
public class HomeController : ControllerBase
{
    private readonly HeroDbContext _dbContext;

    public HomeController(HeroDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    [HttpGet("{id:int}")]
    public async Task<IActionResult> Get(int id, CancellationToken cancellationToken)
    {
        var hero = await _dbContext.Heroes.FirstOrDefaultAsync(e => e.Id == id, cancellationToken);
        var response = new { Data = hero, Successed = hero != null };
        return Ok(response);
    }
}

通过WSL2部署Docker容器的命令:

docker run -d --name ddocker -p 9100:80  -v /mnt/c/Users/chiwenjun/Desktop/pdemo/docs/:/home/db/ ddocker

异常现象

  • 直接修改宿主机/mnt/c/Users/chiwenjun/Desktop/pdemo/docs目录下的SQLite文件,API能正常返回新值;
  • 使用rsync命令同步新SQLite文件替换旧文件后,API始终返回旧数据;
  • 用Python FastAPI编写的查询同一SQLite文件的API可正常返回新值,核心代码如下:
class HeroDbContext:
    def __init__(self, conn_str):
        self.__conn_str = conn_str
        self.__conn = sqlite3.connect(conn_str)

    async def __aenter__(self):
        if self.__conn is None:
            self.__conn = sqlite3.connect(conn_str)
        return self

    async def __aexit__(self, ex_type, ex_value, ex_traceback) -> bool:
        if self.__conn is not None:
            self.__conn.close()
        return True

    def get_by_id(self, id: int) -> Union[Hero, None]:
        try:
            cur = self.__conn.cursor()
            r = cur.execute("SELECT * FROM Heros WHERE Id=:id", [id])
            return self.__handle_db_result(r)
        finally:
            cur.close()

    def __handle_db_result(self, result: Cursor) -> Optional[Hero]:
        if result is None:
            return None
        data = result.fetchone()
        return None if data is None else Hero(data[0], data[1])
问题原因

EF Core Sqlite默认会保持数据库连接长时间打开(HeroDbContext在ASP.NET Core中是作用域实例,连接会被复用),当用rsync替换文件时,操作系统层面的文件句柄仍被EF Core持有,导致程序读取的还是旧文件的内存缓存或句柄指向的旧数据。

而Python代码中,若使用async with语法调用HeroDbContext,每次请求结束后连接会被关闭,下次请求会重新打开文件,因此能读取到新的SQLite文件内容。

解决方案

方案1:关闭EF Core连接池

在DbContext配置中关闭连接池,让每次请求结束后释放连接,下次查询重新打开文件:

// Program.cs/Startup.cs中配置DbContext
builder.Services.AddDbContext<HeroDbContext>(options =>
    options.UseSqlite("Data Source=/home/db/your-db-file.db", 
        sqliteOptions => sqliteOptions.Pooling(false)));

注意:关闭连接池会降低查询性能,需根据业务场景权衡。

方案2:替换文件后重启Docker容器

这是最直接的方式,重启后EF Core会重新建立连接,读取新文件:

docker restart ddocker

方案3:修改文件替换方式

rsync的覆盖写不会触发应用感知文件变更,可先删除旧文件再复制新文件:

# 删除容器内旧文件
docker exec ddocker rm /home/db/your-db-file.db
# 同步新文件
rsync -av /mnt/c/Users/chiwenjun/Desktop/pdemo/docs/your-db-file.db ddocker:/home/db/

注意:该操作会导致短暂的数据库不可用,需做好接口异常处理。

内容的提问来源于stack exchange,提问作者WENJUN CHI

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 03:55:25