1. ホーム
  2. sqlite

[解決済み] System.Data.SQLite Close()でデータベースファイルが解放されない

2022-10-26 19:13:58

質問

ファイルを削除しようとする前にデータベースを閉じてしまうという問題があります。 コードは次のとおりです。

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

そしてDeleteはファイルがまだ使用中であるという例外を投げます。数分後にデバッガでDelete()を再試行しましたので、タイミングの問題ではありません。

トランザクションコードはあるのですが、Close()呼び出しの前に全く実行されないのです。ですから、オープン トランザクションでないことは間違いありません。 openとcloseの間のsqlコマンドは、単なるselectです。

ProcMon は、私のプログラムとウイルス対策ソフトがデータベース ファイルを見ているところを示しています。 私のプログラムが close() の後に db ファイルを解放することは表示されません。

Visual Studio 2010、C#、System.Data.SQLite バージョン 1.0.77.0、Win7

これと同じような 2 年前のバグを見ましたが、変更履歴には修正済みと書かれています。

他に何か確認できることはありますか? 開いているコマンドやトランザクションのリストを取得する方法はありますか?


新しい、動作するコードです。

 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# 用の DB 抽象化レイヤーを書いているときに同じ問題に遭遇しましたが、実際に問題が何であるかを見つけるまでには至りませんでした。結局、私のライブラリを使って SQLite DB を削除しようとすると、例外がスローされるだけでした。

とにかく、今日の午後、私はもう一度すべてに目を通し、なぜそのようなことが起こるのか、きっぱりと見つけ出そうと考えました。

を呼び出すとどうなりますか? SQLiteConnection.Close() は、(多くのチェックや他のものと共に) SQLiteConnectionHandle が SQLite データベースのインスタンスを指していることが破棄されることです。これは SQLiteConnectionHandle.Dispose() の呼び出しによって行われますが、これは CLR のガーベッジコレクタがガベージコレクションを実行するまでポインタを実際に解放するわけではありません。そのため SQLiteConnectionHandle をオーバーライドするので CriticalHandle.ReleaseHandle() 関数を呼び出すように sqlite3_close_interop() (別の関数を通して) これはデータベースを閉じません。

私の観点では、プログラマはデータベースがいつ閉じられるのか実際に分からないので、これは非常に悪い方法です。しかし、これは行われてきた方法なので、今のところこれに耐えるか、System.Data.SQLiteにいくつかの変更をコミットしなければならないと思います。どんなボランティアでもそうすることを歓迎します。残念ながら、私は来年までにそうするための時間が不足しています。

TL;DR 解決策は SQLiteConnection.Close() を呼び出した後 File.Delete() .

以下はサンプルコードです。

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

がんばってください、お役に立てるといいのですが