Ich habe ein Problem beim Schließen meiner Datenbank, bevor versucht wird, die Datei zu löschen. Der Code ist gerecht
myconnection.Close();
File.Delete(filename);
Und das Löschen löst eine Ausnahme aus, dass die Datei noch verwendet wird. Ich habe Delete () im Debugger nach einigen Minuten erneut ausprobiert, es handelt sich also nicht um ein Timing-Problem.
Ich habe einen Transaktionscode, der jedoch vor dem Aufruf von Close () überhaupt nicht ausgeführt wird. Ich bin mir also ziemlich sicher, dass es sich nicht um eine offene Transaktion handelt. Die SQL-Befehle zwischen Öffnen und Schließen sind nur Auswahlen.
ProcMon zeigt mein Programm und mein Antivirenprogramm in der Datenbankdatei. Es zeigt nicht, dass mein Programm die Datenbankdatei nach dem Schließen () freigibt.
Visual Studio 2010, C #, System.Data.SQLite Version 1.0.77.0, Win7
Ich habe einen zwei Jahre alten Fehler wie diesen gesehen, aber das Changelog sagt, dass er behoben ist.
Kann ich noch etwas überprüfen? Gibt es eine Möglichkeit, eine Liste offener Befehle oder Transaktionen abzurufen?
Neuer Arbeitscode:
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);
quelle
SQLiteAsyncConnection.ResetPool()
, finden Sie diese Ausgabe für Details.Antworten:
Ich bin vor einiger Zeit beim Schreiben einer DB-Abstraktionsschicht für C # auf dasselbe Problem gestoßen, und ich bin nie dazu gekommen, herauszufinden, wo das Problem liegt. Ich habe gerade eine Ausnahme ausgelöst, als Sie versucht haben, eine SQLite-Datenbank mithilfe meiner Bibliothek zu löschen.
Wie auch immer, heute Nachmittag habe ich alles noch einmal durchgesehen und mir gedacht, ich würde versuchen herauszufinden, warum das ein für alle Mal so war. Also hier ist, was ich bisher gefunden habe.
Wenn Sie aufrufen,
SQLiteConnection.Close()
wird (zusammen mit einer Reihe von Überprüfungen und anderen Dingen) dasSQLiteConnectionHandle
, was auf die SQLite-Datenbankinstanz verweist, entsorgt. Dies erfolgt über einen Aufruf vonSQLiteConnectionHandle.Dispose()
, der Zeiger wird jedoch erst freigegeben, wenn der Garbage Collector der CLR eine Garbage Collection durchführt. DaSQLiteConnectionHandle
dieCriticalHandle.ReleaseHandle()
aufzurufende Funktionsqlite3_close_interop()
(über eine andere Funktion) überschrieben wird, wird die Datenbank nicht geschlossen.Aus meiner Sicht ist dies eine sehr schlechte Vorgehensweise, da der Programmierer nicht sicher ist, wann die Datenbank geschlossen wird, aber so wurde es gemacht, also müssen wir wohl erst einmal damit leben oder uns verpflichten einige Änderungen an System.Data.SQLite. Freiwillige sind dazu herzlich eingeladen, leider habe ich vor dem nächsten Jahr keine Zeit mehr dazu.
TL; DR Die Lösung besteht darin, einen GC nach Ihrem Anruf bei
SQLiteConnection.Close()
und vor Ihrem Anruf bei zu erzwingenFile.Delete()
.Hier ist der Beispielcode:
Viel Glück damit und ich hoffe es hilft
quelle
Hat
GC.Collect()
bei mir einfach nicht funktioniert.Ich musste hinzufügen
GC.WaitForPendingFinalizers()
nach ,GC.Collect()
um mit dem Löschen von Dateien , um fortzufahren.quelle
GC.Collect()
einfach eine Garbage Collection, die asynchron ist. Um sicherzustellen, dass alles bereinigt wurde, müssen Sie explizit darauf warten.In meinem Fall habe ich
SQLiteCommand
Objekte erstellt, ohne sie explizit zu entsorgen.Ich habe meinen Befehl in eine
using
Anweisung eingeschlossen, die mein Problem behoben hat.Dann ist es auch viel einfacher, Befehle auszuführen.
quelle
Hatte ein ähnliches Problem, obwohl die Garbage Collector-Lösung es nicht behoben hat.
Gefundene Entsorgung
SQLiteCommand
undSQLiteDataReader
Gegenstände nach Gebrauch retteten mich überhaupt mit dem Müllsammler.quelle
SQLiteCommand
auch wenn SieSQLiteCommand
später eine Variable recyceln .command.Dispose();
zu jedemSQLiteCommand
, der ausgeführt wurde, hinzugefügt habe ..Dispose()
Stellen Sie außerdem sicher, dass Sie andere Objekte wie SQLiteTransaction freigeben (z. B. ), falls vorhanden.Folgendes hat bei mir funktioniert:
Weitere Informationen : Verbindungen werden von SQLite zusammengefasst, um die Leistung zu verbessern. Wenn Sie die Close-Methode für ein Verbindungsobjekt aufrufen, ist die Verbindung zur Datenbank möglicherweise noch aktiv (im Hintergrund), sodass die nächste Open-Methode schneller wird. Wenn Sie das wissen Wenn Sie keine neue Verbindung mehr möchten, werden durch Aufrufen von ClearAllPools alle im Hintergrund aktiven Verbindungen geschlossen und die Dateihandles zur Datenbankdatei freigegeben. Anschließend wird die Datenbankdatei möglicherweise entfernt, gelöscht oder von einem anderen Prozess verwendet.
quelle
SQLiteConnectionPool.Shared.Reset()
. Dadurch werden alle offenen Verbindungen geschlossen. Dies ist insbesondere dann eine Lösung, wenn SieSQLiteAsyncConnection
keineClose()
Methode verwenden.Ich hatte ein ähnliches Problem, ich habe die Lösung mit versucht,
GC.Collect
aber wie bereits erwähnt, kann es lange dauern, bis die Datei nicht gesperrt wird.Ich habe eine alternative Lösung gefunden, bei der die zugrunde liegenden
SQLiteCommand
s in den TableAdapters entsorgt werden. Weitere Informationen finden Sie in dieser Antwort .quelle
Versuchen Sie dies ... dieser versucht alle oben genannten Codes ... hat für mich funktioniert
hoffentlich hilft das
quelle
Ich habe das gleiche Problem mit EF und
System.Data.Sqlite
.Für mich fand
SQLiteConnection.ClearAllPools()
undGC.Collect()
reduzierte ich , wie oft das Sperren von Dateien passieren würde, aber es kam immer noch gelegentlich vor (in etwa 1% der Fälle).Ich habe nachgeforscht und es scheint, dass einige von
SQLiteCommand
EF erstellte s nicht entsorgt sind und ihre Connection-Eigenschaft immer noch auf die geschlossene Verbindung festgelegt ist. Ich habe versucht, diese zu entsorgen, aber Entity Framework hat dann beim nächstenDbContext
Lesen eine Ausnahme ausgelöst - anscheinend verwendet EF sie manchmal noch, nachdem die Verbindung geschlossen wurde.Meine Lösung bestand darin, sicherzustellen,
Null
dass die Verbindungseigenschaft auf gesetzt ist, wenn die Verbindung auf diesenSQLiteCommand
s geschlossen wird. Dies scheint ausreichend zu sein, um die Dateisperre aufzuheben. Ich habe den folgenden Code getestet und nach einigen tausend Tests keine Probleme mit der Dateisperre festgestellt:Zur Verwendung rufen Sie einfach
ClearSQLiteCommandConnectionHelper.Initialise();
zu Beginn des Anwendungsladens auf. Dadurch wird eine Liste der aktiven Befehle geführt und deren Verbindung festgelegt,Null
wenn sie auf eine geschlossene Verbindung verweisen.quelle
Verwenden
GC.WaitForPendingFinalizers()
Beispiel:
quelle
Hatte ein ähnliches Problem. Garbage Collector anzurufen hat mir nicht geholfen. Später habe ich einen Weg gefunden, das Problem zu lösen
Der Autor schrieb auch, dass er SELECT-Abfragen an diese Datenbank durchgeführt hat, bevor er versucht hat, sie zu löschen. Ich habe die gleiche Situation.
Ich habe folgenden Code:
Außerdem muss ich die Datenbankverbindung nicht schließen und Garbage Collector aufrufen. Ich musste lediglich den Reader schließen, der beim Ausführen der SELECT-Abfrage erstellt wurde
quelle
Ich glaube, der Anruf bei
SQLite.SQLiteConnection.ClearAllPools()
ist die sauberste Lösung. Soweit ich weiß, ist es nicht richtig,GC.Collect()
die WPF-Umgebung manuell aufzurufen . Das Problem ist mir jedoch erstSystem.Data.SQLite
aufgefallen , als ich 3/2016 auf 1.0.99.0 aktualisiert habequelle
Vielleicht müssen Sie sich überhaupt nicht mit GC befassen. Bitte überprüfen Sie, ob alles
sqlite3_prepare
abgeschlossen ist.Für jeden
sqlite3_prepare
benötigen Sie einen Korrespondentensqlite3_finalize
.Wenn Sie nicht korrekt abschließen,
sqlite3_close
wird die Verbindung nicht geschlossen.quelle
Ich hatte mit dem ähnlichen Problem zu kämpfen. Schande über mich ... Endlich wurde mir klar, dass der Reader nicht geschlossen war. Aus irgendeinem Grund dachte ich, dass der Reader geschlossen wird, wenn die entsprechende Verbindung geschlossen wird. Offensichtlich hat GC.Collect () bei mir nicht funktioniert.
Es ist auch eine gute Idee, den Reader mit der Anweisung "using:" zu versehen. Hier ist ein kurzer Testcode.
quelle
Ich habe SQLite 1.0.101.0 mit EF6 verwendet und Probleme mit dem Sperren der Datei, nachdem alle Verbindungen und Entitäten entsorgt wurden.
Dies wurde noch schlimmer, da Aktualisierungen von der EF die Datenbank nach Abschluss gesperrt hielten. GC.Collect () war die einzige Problemumgehung, die half, und ich begann zu verzweifeln.
In meiner Verzweiflung habe ich Oliver Wickendens ClearSQLiteCommandConnectionHelper ausprobiert (siehe seine Antwort vom 8. Juli). Fantastisch. Alle Schließprobleme weg! Danke Oliver.
quelle
Das Warten auf Garbage Collector gibt die Datenbank möglicherweise nicht immer frei, und das ist mir passiert. Wenn in der SQLite-Datenbank eine Ausnahme auftritt, z. B. beim Versuch, eine Zeile mit dem vorhandenen Wert für PrimaryKey einzufügen, wird die Datenbankdatei gespeichert, bis Sie sie entsorgen. Der folgende Code fängt eine SQLite-Ausnahme ab und bricht den problematischen Befehl ab.
Wenn Sie die Ausnahmen problematischer Befehle nicht behandeln, kann Garbage Collector nichts dagegen tun, da es einige nicht behandelte Ausnahmen zu diesen Befehlen gibt, sodass sie kein Müll sind. Diese Handhabungsmethode hat bei mir gut funktioniert, wenn ich auf den Müllsammler gewartet habe.
quelle
Dies funktioniert bei mir, aber ich habe festgestellt, dass manchmal Journaldateien -wal -shm nicht gelöscht werden, wenn der Prozess geschlossen wird. Wenn SQLite -wal -shm-Dateien entfernen soll, wenn alle Verbindungen geschlossen sind, MUSS die zuletzt geschlossene Verbindung nicht schreibgeschützt sein. Hoffe das wird jemandem helfen.
quelle
Beste Antwort, die für mich funktioniert hat.
quelle