System.Data.SQLite Close() not releasing database

2019-01-02 20:15发布

I'm having a problem closing my database before an attempt to delete the file. The code is just

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

And the Delete throws an exception that the file is still in use. I've re-tried the Delete() in the debugger after a few minutes, so it's not a timing issue.

I have transaction code but it doesn't run at all before the Close() call. So I'm fairly sure it's not an open transaction. The sql commands between open and close are just selects.

ProcMon shows my program and my antivirus looking at the database file. It does not show my program releasing the db file after the close().

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

I saw a two year old bug just like this but the changelog says it's fixed.

Is there anything else I can check? Is there a way to get a list of any open commands or transactions?


New, working code:

 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);

16条回答
只靠听说
2楼-- · 2019-01-02 21:07

I was struggling with the similar problem. Shame on me... I finally realized that Reader was not closed. For some reason I was thinking that the Reader will be closed when corresponding connection is closed. Obviously, GC.Collect() didn't work for me.
Wrapping the Reader with "using: statement is also a good idea. Here is a quick test code.

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();
        }
    }   
}
查看更多
像晚风撩人
3楼-- · 2019-01-02 21:08

Try this... this one tries all the above codes... worked for me

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

Hope that helps

查看更多
步步皆殇っ
4楼-- · 2019-01-02 21:08

This works for me but i noticed sometimes journal files -wal -shm are not deleted when the process is closed. If you want SQLite to remove -wal -shm files when all connection are close the last connection closed MUST BE non-readonly. Hope this will help someone.

查看更多
与君花间醉酒
5楼-- · 2019-01-02 21:12

I believe the call to SQLite.SQLiteConnection.ClearAllPools() is the cleanest solution. As far as I know it is not proper to manually call GC.Collect() in the WPF environment. Although, I did not notice the problem until I have upgraded to System.Data.SQLite 1.0.99.0 in 3/2016

查看更多
只若初见
6楼-- · 2019-01-02 21:13

Maybe you don't need to deal with GC at all. Please, check if all sqlite3_prepare is finalized.

For each sqlite3_prepare, you need a correspondent sqlite3_finalize.

If you don't finalize correctly, sqlite3_close will not close the connection.

查看更多
低头抚发
7楼-- · 2019-01-02 21:14

Had a similar issue, though the garbage collector solution didn't fix it.

Found disposing of SQLiteCommand and SQLiteDataReader objects after use saved me using the garbage collector at all.

SQLiteCommand command = new SQLiteCommand(sql, db);
command.ExecuteNonQuery();
command.Dispose();
查看更多
登录 后发表回答