SQLite数据库文件句柄从未关闭 C#

3

我正试图从我的C#应用程序中删除一个SQLite数据库文件。同一应用程序通过每次创建和处理新连接来执行多个可读写(RW)查询。

当尝试删除数据库时(在我可以保证程序没有查询数据库的时刻,因此没有活动连接),我遇到了以下错误:

IOException: The process cannot gain access to <filename> because is being used by another process.

我调查了几个小时:我的代码,Stack Overflow 的问题,使用 procmon 和 resmon 确保我的进程是唯一持有文件活动句柄的进程。

在所有这些之后,我确定每当创建一个数据库连接时,DB 文件没有被正确关闭。下面是解释:

我有以下函数来执行查询并将结果加载到 DataTable 中:

public DataTable PerformQuery(string query) {
    try {
        DataTable table = new DataTable();
        using(SQLiteConnection connection = new SQLiteConnection(connString)) {
            SQLiteCommand cmd = connection.CreateCommand();
            cmd.CommandText = query;
            connection.Open();
            if (!query.StartsWith("SELECT")) {
                cmd.ExecuteNonQuery();
            } else {
                SQLiteDataReader reader = cmd.ExecuteReader();
                FillTable(reader, table);
            }
            // Despite using the using scope, close and dispose the connection manually
            connection.Close();
            connection.Dispose();
        }
        // Kill all pools and call GC
        SQLiteConnection.ClearAllPools();
        GC.Collect();
        GC.WaitForPendingFinalizers();
        return table;
    } catch (Exception ex) {
        // Handle error... (not relevant)
        return null;
    }
}

嗯,使用SysInternals的handle.exe在一个无限循环中(每秒运行一次),并使用Visual Studio的调试器逐步调试程序,我发现尽管:

  • 调用Close
  • 调用Dispose
  • 退出using范围
  • 杀死所有池
  • 执行GC并等待其完成

我的DB文件的文件句柄没有被关闭。

我真的需要从代码内部删除我的DB文件,但由于文件句柄从未关闭,我无法这样做。

我该如何解决这个问题?

编辑1:

  • 使用.NET Winforms应用程序和System.Data.SQLite
  • 已经尝试将Pooling=false添加到连接字符串中。

这是.NET Framework、EFCore还是其他什么? - Mark Benningfield
.NET,Winform应用程序。使用System.Data.SQLite - PauMAVA
尝试在连接字符串中添加“Pooling=false”。也就是说,不要使用连接池。 - Mark Benningfield
感谢您的建议。不幸的是,我已经尝试过这个方法,但仍然没有成功。 - PauMAVA
SQLiteCommand 也是可处理的对象。尝试进行处理。 - Rogerson Nazário
将相同的处理方式应用到SQLiteDataReader的释放。 - Rogerson Nazário
1个回答

0

你尝试过同时关闭SQLiteCommand吗?

using (SQLiteConnection connection = new SQLiteConnection(connString)) {
    using (SQLiteCommand cmd = connection.CreateCommand()){
        // do stuff here
    }
}
SQLiteConnection.ClearAllPools();
GC.Collect();
GC.WaitForPendingFinalizers();

1
目前您的答案写得不清楚。请进行[编辑]以添加更多细节,以帮助其他人了解这如何回答所提出的问题。您可以在帮助中心上找到有关编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接