System.Data.SQLiteclosures()不释放数据库文件

试图删除文件之前,我遇到了closures数据库的问题。 代码只是

myconnection.Close(); File.Delete(filename); 

而且删除引发了一个exception,即该文件仍在使用中。 几分钟后,我在debugging器中重新尝试了Delete(),所以这不是时序问题。

我有事务代码,但它在Close()调用之前根本不运行。 所以我相当确定这不是一个公开交易。 打开和closures之间的sql命令只是select。

ProcMon显示我的程序和我的防病毒看数据库文件。 它不显示我的程序在close()之后释放db文件。

Visual Studio 2010,C#,System.Data.SQLite版本1.0.77.0,Win7

我看到一个两年前的bug,但是更新日志说这个bug是固定的。

还有什么我可以检查? 有没有办法获得任何打开的命令或交易清单?


新的工作代码:

  db.Close(); GC.Collect(); // yes, really release the db bool worked = false; int tries = 1; while ((tries < 4) && (!worked)) { try { Thread.Sleep(tries * 100); File.Delete(filename); worked = true; } catch (IOException e) // delete only throws this on locking { tries++; } } if (!worked) throw new IOException("Unable to close file" + filename); 

刚刚遇到同样的问题,而为C#编写一个数据库抽象层,我从来没有真正find问题是什么。 当您试图使用我的库删除SQLite数据库时,我刚刚抛出一个exception。

无论如何,今天下午,我又一遍又一遍地看了一遍,发现我会试着找出为什么这样做是一劳永逸的,所以这里是我迄今为止发现的。

当你调用SQLiteConnection.Close()时会发生什么(以及一些检查和其他事情), SQLiteConnectionHandle指向SQLite数据库实例。 这是通过调用SQLiteConnectionHandle.Dispose() ,但是直到CLR的垃圾收集器执行一些垃圾回收之前,这并不会释放指针。 由于SQLiteConnectionHandle重写了CriticalHandle.ReleaseHandle()函数来调用sqlite3_close_interop() (通过另一个函数),因此不会closures数据库。

从我的angular度来看,这是一种非常糟糕的做事方式,因为程序员在数据库被closures时实际上并不确定,但是这样做已经结束了,所以我想我们现在必须忍受它,或者提交对System.Data.SQLite进行一些更改。 欢迎任何志愿者这样做,不幸的是我明年之前就没有时间这样做了。

TL; DR解决方法是在调用SQLiteConnection.Close()之后,在调用SQLiteConnection.Close()之前强制GC。

这里是示例代码:

 string filename = "testFile.db"; SQLiteConnection connection = new SQLiteConnection("Data Source=" + filename + ";Version=3;"); connection.Close(); GC.Collect(); File.Delete(filename); 

祝你好运,我希望它有帮助

只是GC.Collect()没有为我工作。

我不得不在GC.Collect() GC.WaitForPendingFinalizers()之后添加GC.WaitForPendingFinalizers()以继续删除文件。

在我的情况下,我创build的SQLiteCommand对象没有明确处置它们。

 var command = connection.CreateCommand(); command.CommandText = commandText; value = command.ExecuteScalar(); 

我在using声明中包装了我的命令,并解决了我的问题。

 static public class SqliteExtensions { public static object ExecuteScalar(this SQLiteConnection connection, string commandText) { using (var command = connection.CreateCommand()) { command.CommandText = commandText; return command.ExecuteScalar(); } } } 

using语句确保即使发生exception也会调用Dispose。

那么执行命令也会更容易。

 value = connection.ExecuteScalar(commandText) // Command object created and disposed 

我遇到了类似的问题,我用GC.Collect尝试了解决scheme,但是如前所述,可能需要很长时间才能locking文件。

我发现了一个替代解决scheme,它涉及TableAdapters中底层SQLiteCommand的处理,请参阅此答案以获取更多信息。

以下为我工作:

 MySQLiteConnection.Close(); SQLite.SQLiteConnection.ClearAllPools() 

更多信息 :为了提高性能,连接被SQLite汇集起来。这意味着当你在一个连接对象上调用Close方法时,与数据库的连接可能仍然活着(在后台),以便下一个Open方法变得更快。当你知道你不再需要一个新的连接,调用ClearAllPoolsclosures所有在后台活动的连接和文件句柄(s?)到获得释放的db文件。然后db文件可能被删除,删除或被另一个进程使用。

有一个类似的问题,尽pipe垃圾收集器解决scheme没有解决它。

使用后发现SQLiteCommandSQLiteDataReader对象的处理SQLiteCommand使用垃圾回收器保存了我。

 SQLiteCommand command = new SQLiteCommand(sql, db); command.ExecuteNonQuery(); command.Dispose(); 

我相信对SQLite.SQLiteConnection.ClearAllPools()的调用是最干净的解决scheme。 据我所知,在WPF环境中手动调用GC.Collect()是不合适的。 虽然,我没有注意到这个问题,直到我已经在3/2016升级到System.Data.SQLite 1.0.99.0

我正在与类似的问题挣扎。 对我感到羞耻…我终于意识到, 读者并没有closures。 出于某种原因,我认为当相应的连接closures时,Reader将被closures。 显然,GC.Collect()不适合我。
用“using:语句包装读者”也是一个好主意,下面是一个快速的testing代码。

 static void Main(string[] args) { try { var dbPath = "myTestDb.db"; ExecuteTestCommand(dbPath); File.Delete(dbPath); Console.WriteLine("DB removed"); } catch (Exception e) { Console.WriteLine(e.Message); } Console.Read(); } private static void ExecuteTestCommand(string dbPath) { using (var connection = new SQLiteConnection("Data Source=" + dbPath + ";")) { using (var command = connection.CreateCommand()) { command.CommandText = "PRAGMA integrity_check"; connection.Open(); var reader = command.ExecuteReader(); if (reader.Read()) Console.WriteLine(reader.GetString(0)); //without next line database file will remain locked reader.Close(); } } } 

试试这个…这个尝试所有上面的代码 …为我工作

  Reader.Close() connection.Close() GC.Collect() GC.WaitForPendingFinalizers() command.Dispose() SQLite.SQLiteConnection.ClearAllPools() 

希望有所帮助

也许你根本不需要处理GC。 请检查是否所有的sqlite3_prepare已经完成。

对于每个sqlite3_prepare ,你需要一个记者sqlite3_finalize

如果你没有正确定稿, sqlite3_close将不会closures连接。

我一直与EF和System.Data.Sqlite相同的问题。

对于我来说,我发现SQLiteConnection.ClearAllPools()GC.Collect()会减less文件locking发生的频率,但仍然偶尔会发生(大约1%的时间)。

我一直在调查,似乎是EF创build的一些SQLiteCommand不处置,仍然有他们的连接属性设置为closures的连接。 我试图处理这些,但entity framework然后会在下一个DbContext阅读过程中抛出一个exception – 看来EF有时仍然在连接closures后使用它们。

我的解决scheme是确保连接closures这些SQLiteCommand时连接属性设置为Null 。 这似乎足以释放文件locking。 我已经testing了下面的代码,在几千次testing之后没有看到任何文件locking问题:

 public static class ClearSQLiteCommandConnectionHelper { private static readonly List<SQLiteCommand> OpenCommands = new List<SQLiteCommand>(); public static void Initialise() { SQLiteConnection.Changed += SqLiteConnectionOnChanged; } private static void SqLiteConnectionOnChanged(object sender, ConnectionEventArgs connectionEventArgs) { if (connectionEventArgs.EventType == SQLiteConnectionEventType.NewCommand && connectionEventArgs.Command is SQLiteCommand) { OpenCommands.Add((SQLiteCommand)connectionEventArgs.Command); } else if (connectionEventArgs.EventType == SQLiteConnectionEventType.DisposingCommand && connectionEventArgs.Command is SQLiteCommand) { OpenCommands.Remove((SQLiteCommand)connectionEventArgs.Command); } if (connectionEventArgs.EventType == SQLiteConnectionEventType.Closed) { var commands = OpenCommands.ToList(); foreach (var cmd in commands) { if (cmd.Connection == null) { OpenCommands.Remove(cmd); } else if (cmd.Connection.State == ConnectionState.Closed) { cmd.Connection = null; OpenCommands.Remove(cmd); } } } } } 

要使用只需调用ClearSQLiteCommandConnectionHelper.Initialise(); 在应用程序加载的开始。 这将保存活动命令的列表,并将它们的连接设置为Null当他们指向一个closures的连接。

我正在使用SQLite 1.0.101.0与EF6和文件被locking后,所有的连接和实体处置。

在EF完成之后数据库被locking的情况下,这个更新会变得更糟。 GC.Collect()是唯一的解决方法,我开始绝望。

无奈之下,我尝试了Oliver Wickenden的ClearSQLiteCommandConnectionHelper(请参阅他7月8日的回答)。 太棒了。 所有locking问题都没有了 谢谢奥利弗

使用GC.WaitForPendingFinalizers()

例:

 Con.Close(); GC.Collect();` GC.WaitForPendingFinalizers(); File.Delete(Environment.CurrentDirectory + "\\DATABASENAME.DB"); 

有类似的问题。 调用垃圾收集器没有帮助我。 LATER我find了解决问题的方法

作者还写道,他试图删除它之前对该数据库执行SELECT查询。 我有同样的情况。

我有以下代码:

 SQLiteConnection bc; string sql; var cmd = new SQLiteCommand(sql, bc); SQLiteDataReader reader = cmd.ExecuteReader(); reader.Read(); reader.Close(); // when I added that string, the problem became solved. 

另外,我不需要closures数据库连接并调用垃圾收集器。 我所要做的就是closures在执行SELECT查询时创build的读取器