Tom*_*rul 82 sqlite system.data.sqlite
在尝试删除文件之前,我在关闭数据库时遇到问题.代码就是这样
myconnection.Close();
File.Delete(filename);
Run Code Online (Sandbox Code Playgroud)
并且Delete抛出了一个异常,即该文件仍在使用中.几分钟后我在调试器中重新尝试了Delete(),所以这不是时间问题.
我有事务代码,但在Close()调用之前它根本不运行.所以我很确定这不是一个开放的交易.打开和关闭之间的sql命令只是选择.
ProcMon显示我的程序和我的防病毒软件查看数据库文件.它没有显示我的程序在close()之后释放db文件.
Visual Studio 2010,C#,System.Data.SQLite版本1.0.77.0,Win7
我看到一个两岁的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);
Run Code Online (Sandbox Code Playgroud)
Ben*_*ell 94
前一段时间遇到同样的问题,同时为C#编写了一个DB抽象层,我从来没有真正找到问题所在.当您尝试使用我的库删除SQLite数据库时,我刚刚抛出异常.
无论如何,今天下午我再次仔细研究了这一切,并想到我会试着找出为什么一劳永逸地这样做,所以这就是我迄今为止所发现的.
当你调用时会发生什么SQLiteConnection.Close()(以及一些检查和其他事情)SQLiteConnectionHandle指向SQLite数据库实例的处理.这是通过调用来完成的SQLiteConnectionHandle.Dispose(),但是在CLR的垃圾收集器执行一些垃圾收集之前,这实际上并没有释放指针.由于SQLiteConnectionHandle覆盖了CriticalHandle.ReleaseHandle()要调用的函数sqlite3_close_interop()(通过另一个函数),因此不会关闭数据库.
从我的观点来看,这是一种非常糟糕的做事方式,因为程序员实际上并不确定数据库何时关闭,但这就是它已经完成的方式所以我想我们现在必须忍受它,或者提交System.Data.SQLite的一些更改.欢迎任何志愿者这样做,不幸的是我在明年之前没有时间这样做.
TL; DR
解决方案是在您致电SQLiteConnection.Close()之前和之后强制使用GC File.Delete().
以下是示例代码:
string filename = "testFile.db";
SQLiteConnection connection = new SQLiteConnection("Data Source=" + filename + ";Version=3;");
connection.Close();
GC.Collect();
GC.WaitForPendingFinalizers();
File.Delete(filename);
Run Code Online (Sandbox Code Playgroud)
祝它好运,我希望它有所帮助
小智 55
只是GC.Collect()没有为我工作.
我必须添加GC.WaitForPendingFinalizers()以后GC.Collect()才能继续删除文件.
Nat*_*ate 17
在我的情况下,我在SQLiteCommand没有明确处理它们的情况下创建对象.
var command = connection.CreateCommand();
command.CommandText = commandText;
value = command.ExecuteScalar();
Run Code Online (Sandbox Code Playgroud)
我把我的命令包装在一个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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
该
using语句确保即使发生异常也会调用Dispose.
然后执行命令也容易得多.
value = connection.ExecuteScalar(commandText)
// Command object created and disposed
Run Code Online (Sandbox Code Playgroud)
Arv*_*vin 11
以下对我有用:
MySQLiteConnection.Close();
SQLite.SQLiteConnection.ClearAllPools()
Run Code Online (Sandbox Code Playgroud)
更多信息:连接由SQLite汇集以提高性能.这意味着当您在连接对象上调用Close方法时,与数据库的连接可能仍然存在(在后台),以便下一个Open方法变得更快.当您知道您不再需要新连接,调用ClearAllPools会关闭后台中存活的所有连接,并且db文件的文件句柄(s?)将被释放.然后,另一个进程可能会删除,删除或使用db文件.
小智 11
有一个类似的问题,虽然垃圾收集器解决方案没有解决它.
在使用后发现处理SQLiteCommand和SQLiteDataReader对象使用垃圾收集器保存我.
SQLiteCommand command = new SQLiteCommand(sql, db);
command.ExecuteNonQuery();
command.Dispose();
Run Code Online (Sandbox Code Playgroud)
我在 EF 和System.Data.Sqlite.
对我来说,我发现SQLiteConnection.ClearAllPools()并GC.Collect()会减少文件锁定发生的频率,但它仍然偶尔会发生(大约 1% 的时间)。
我一直在调查,似乎SQLiteCommandEF 创建的某些s 没有被处理,并且它们的 Connection 属性仍然设置为关闭的连接。我尝试处理这些但实体框架会在下一次DbContext读取期间抛出异常- 似乎 EF 有时在连接关闭后仍然使用它们。
我的解决方案是确保Null在这些SQLiteCommands上关闭连接时将Connection 属性设置为。这似乎足以释放文件锁。我一直在测试下面的代码,经过几千次测试后没有看到任何文件锁定问题:
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);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用只需ClearSQLiteCommandConnectionHelper.Initialise();在应用程序加载开始时调用。然后,这将保留活动命令的列表,并Null在它们指向已关闭的连接时将它们的 Connection 设置为。
小智 5
试试这个……这个尝试了上面所有的代码……对我有用
Reader.Close()
connection.Close()
GC.Collect()
GC.WaitForPendingFinalizers()
command.Dispose()
SQLite.SQLiteConnection.ClearAllPools()
Run Code Online (Sandbox Code Playgroud)
希望有帮助
小智 5
使用GC.WaitForPendingFinalizers()
例子:
Con.Close();
GC.Collect();`
GC.WaitForPendingFinalizers();
File.Delete(Environment.CurrentDirectory + "\\DATABASENAME.DB");
Run Code Online (Sandbox Code Playgroud)