120 votes

System.Data.SQLite Close() ne libère pas le fichier de base de données

J'ai un problème pour fermer ma base de données avant d'essayer de supprimer le fichier. Le code est juste

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

Et l'application Delete lève une exception en indiquant que le fichier est toujours en cours d'utilisation. J'ai réessayé le Delete() dans le débogueur après quelques minutes, ce n'est donc pas un problème de timing.

J'ai le code de la transaction mais il ne s'exécute pas du tout avant l'appel à Close(). Je suis donc presque sûr qu'il ne s'agit pas d'une transaction ouverte. Les commandes sql entre open et close sont juste des selects.

ProcMon montre mon programme et mon antivirus en train d'examiner le fichier de la base de données. Il ne montre pas que mon programme libère le fichier db après le close().

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

J'ai vu un bug vieux de deux ans exactement comme celui-ci, mais le changelog dit qu'il est corrigé.

Y a-t-il autre chose à vérifier ? Existe-t-il un moyen d'obtenir une liste des commandes ou des transactions en cours ?


Nouveau, code de travail :

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

3voto

Jona Varque Points 21

Je crois que l'appel à SQLite.SQLiteConnection.ClearAllPools() est la solution la plus propre. Pour autant que je sache, il n'est pas correct d'appeler manuellement GC.Collect() dans l'environnement WPF. Bien que je n'aie pas remarqué le problème avant d'être passé à la version System.Data.SQLite 1.0.99.0 en 3/2016

3voto

Schullz Points 283

J'ai eu un problème similaire. L'appel à Garbage Collector ne m'a pas aidé. Plus tard, j'ai trouvé un moyen de résoudre le problème

L'auteur a également écrit qu'il avait effectué des requêtes SELECT dans cette base de données avant d'essayer de la supprimer. Je suis dans la même situation.

J'ai le code suivant :

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.

De plus, je n'ai pas besoin de fermer la connexion à la base de données et d'appeler le collecteur de déchets. Tout ce que j'ai eu à faire, c'est de fermer le lecteur qui a été créé lors de l'exécution de la requête SELECT.

2voto

Mike Znaet Points 79

J'étais confronté à un problème similaire. Honte à moi... J'ai finalement réalisé que Lecteur n'a pas été fermée. Pour une raison quelconque, je pensais que le lecteur serait fermé lorsque la connexion correspondante serait fermée. Manifestement, GC.Collect() n'a pas fonctionné pour moi.
Il est également judicieux d'entourer le lecteur d'une déclaration "using :". Voici un code de test rapide.

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

2voto

João Monteiro Points 66

Peut-être n'avez-vous pas besoin de vous occuper de la GC du tout. Veuillez vérifier si tous les sqlite3_prepare est finalisé.

Pour chaque sqlite3_prepare Vous avez besoin d'un correspondant sqlite3_finalize .

Si vous ne finalisez pas correctement, sqlite3_close ne fermera pas la connexion.

1voto

ekalchev Points 92

Cela fonctionne pour moi mais j'ai remarqué que parfois les fichiers journaux -wal -shm ne sont pas supprimés lorsque le processus est fermé. Si vous voulez que SQLite supprime les fichiers -wal -shm lorsque toutes les connexions sont fermées, la dernière connexion fermée DOIT être en lecture seule. J'espère que

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X