Saya mengalami masalah saat menutup database saya sebelum mencoba menghapus file. Kode itu adil
myconnection.Close();
File.Delete(filename);
Dan Hapus memunculkan pengecualian bahwa file tersebut masih digunakan. Saya telah mencoba kembali Delete () di debugger setelah beberapa menit, jadi ini bukan masalah waktu.
Saya memiliki kode transaksi tetapi tidak berjalan sama sekali sebelum panggilan Close (). Jadi saya cukup yakin ini bukan transaksi terbuka. Perintah sql antara buka dan tutup hanya memilih.
ProcMon menunjukkan program saya dan antivirus saya melihat file database. Itu tidak menunjukkan program saya merilis file db setelah close ().
Visual Studio 2010, C #, System.Data.SQLite versi 1.0.77.0, Win7
Saya melihat bug berumur dua tahun seperti ini tetapi changelog mengatakan itu sudah diperbaiki.
Apakah ada hal lain yang bisa saya periksa? Apakah ada cara untuk mendapatkan daftar perintah atau transaksi yang terbuka?
Baru, kode yang berfungsi:
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);
sumber
SQLiteAsyncConnection.ResetPool()
, lihat masalah ini untuk detailnya.Jawaban:
Mengalami masalah yang sama beberapa waktu yang lalu saat menulis lapisan abstraksi DB untuk C # dan saya tidak pernah benar-benar menemukan apa masalahnya. Saya baru saja melempar pengecualian ketika Anda mencoba menghapus SQLite DB menggunakan perpustakaan saya.
Bagaimanapun, sore ini saya melihat semuanya lagi dan berpikir saya akan mencoba dan mencari tahu mengapa melakukannya sekali dan untuk semua, jadi inilah yang saya temukan sejauh ini.
Apa yang terjadi ketika Anda memanggil
SQLiteConnection.Close()
adalah (bersama dengan sejumlah pemeriksaan dan hal-hal lain)SQLiteConnectionHandle
yang menunjuk ke contoh database SQLite dibuang. Ini dilakukan melalui panggilan keSQLiteConnectionHandle.Dispose()
, namun ini tidak benar-benar melepaskan penunjuk sampai Kolektor Sampah CLR melakukan beberapa pengumpulan sampah. KarenaSQLiteConnectionHandle
menggantiCriticalHandle.ReleaseHandle()
fungsi yang akan dipanggilsqlite3_close_interop()
(melalui fungsi lain) ini tidak menutup database.Dari sudut pandang saya, ini adalah cara yang sangat buruk untuk melakukan sesuatu karena programmer sebenarnya tidak yakin kapan database ditutup, tapi begitulah cara melakukannya, jadi saya kira kita harus menerimanya untuk saat ini, atau berkomitmen sedikit perubahan pada System.Data.SQLite. Semua sukarelawan dipersilakan untuk melakukannya, sayangnya saya kehabisan waktu sebelum tahun depan.
TL; DR Solusinya adalah dengan memaksa GC setelah panggilan Anda ke
SQLiteConnection.Close()
dan sebelum panggilan Anda keFile.Delete()
.Berikut ini contoh kode:
Semoga berhasil, dan saya harap ini membantu
sumber
Hanya
GC.Collect()
saja tidak berhasil untukku.Saya harus menambahkan
GC.WaitForPendingFinalizers()
setelahGC.Collect()
untuk melanjutkan dengan penghapusan file.sumber
GC.Collect()
hanya memulai pengumpulan sampah yang tidak sinkron jadi untuk memastikan semua telah dibersihkan, Anda harus menunggunya secara eksplisit.Dalam kasus saya, saya membuat
SQLiteCommand
objek tanpa secara eksplisit membuangnya.Saya membungkus perintah saya dalam sebuah
using
pernyataan dan itu memperbaiki masalah saya.Maka jauh lebih mudah untuk menjalankan perintah juga.
sumber
Punya masalah serupa, meskipun solusi pengumpul sampah tidak memperbaikinya.
Ditemukan pembuangan
SQLiteCommand
danSQLiteDataReader
objek setelah digunakan menyelamatkan saya menggunakan pengumpul sampah sama sekali.sumber
SQLiteCommand
bahkan jika Anda mendaur ulangSQLiteCommand
variabel nanti.command.Dispose();
ke setiapSQLiteCommand
yang dieksekusi..Dispose()
) objek lain seperti SQLiteTransaction, jika Anda punya.Yang berikut berhasil untuk saya:
Info selengkapnya : Koneksi dikumpulkan oleh SQLite untuk meningkatkan kinerja, artinya saat Anda memanggil metode Tutup pada objek koneksi, koneksi ke database mungkin masih hidup (di latar belakang) sehingga metode Buka berikutnya menjadi lebih cepat. Anda tidak menginginkan koneksi baru lagi, memanggil ClearAllPools akan menutup semua koneksi yang hidup di latar belakang dan file handle (s?) ke file db akan dirilis. Kemudian file db dapat dihapus, dihapus atau digunakan oleh proses lain.
sumber
SQLiteConnectionPool.Shared.Reset()
. Ini akan menutup semua koneksi yang terbuka. Secara khusus, ini adalah solusi jika Anda menggunakanSQLiteAsyncConnection
yang tidak memilikiClose()
metode.Saya mengalami masalah yang sama, saya sudah mencoba solusinya
GC.Collect
tetapi, seperti yang disebutkan, bisa memakan waktu lama sebelum file menjadi tidak terkunci.Saya telah menemukan solusi alternatif yang melibatkan pembuangan yang mendasari
SQLiteCommand
di TabelAdapters, lihat jawaban ini untuk informasi tambahan.sumber
Saya mengalami masalah yang sama dengan EF dan
System.Data.Sqlite
.Bagi saya, saya menemukan
SQLiteConnection.ClearAllPools()
danGC.Collect()
akan mengurangi seberapa sering penguncian file akan terjadi tetapi kadang-kadang masih terjadi (Sekitar 1% dari waktu).Saya telah menyelidiki dan tampaknya beberapa
SQLiteCommand
yang EF buat tidak dibuang dan properti Koneksi mereka masih disetel ke koneksi tertutup. Saya mencoba membuang ini tetapi Entity Framework kemudian akan mengeluarkan pengecualian selamaDbContext
pembacaan berikutnya - tampaknya EF terkadang masih menggunakannya setelah koneksi ditutup.Solusi saya adalah memastikan properti Connection diatur ke
Null
saat koneksi ditutup padaSQLiteCommand
s ini . Ini sepertinya cukup untuk membuka kunci file. Saya telah menguji kode di bawah ini dan tidak melihat masalah kunci file apa pun setelah beberapa ribu pengujian:Untuk menggunakan panggil saja
ClearSQLiteCommandConnectionHelper.Initialise();
pada awal pemuatan aplikasi. Ini kemudian akan menyimpan daftar perintah aktif dan akan mengatur KoneksiNull
mereka ketika mereka menunjuk ke koneksi yang ditutup.sumber
Coba ini ... yang ini mencoba semua kode di atas ... berhasil untuk saya
Semoga membantu
sumber
Menggunakan
GC.WaitForPendingFinalizers()
Contoh:
sumber
Punya masalah serupa. Memanggil Pengumpul Sampah tidak membantu saya. LAter Saya menemukan cara untuk memecahkan masalah
Penulis juga menulis bahwa dia melakukan kueri SELECT ke database itu sebelum mencoba menghapusnya. Saya memiliki situasi yang sama.
Saya memiliki kode berikut:
Selain itu, saya tidak perlu menutup koneksi database dan memanggil Pengumpul Sampah. Yang harus saya lakukan adalah menutup pembaca yang dibuat saat menjalankan kueri SELECT
sumber
Saya percaya panggilan ke
SQLite.SQLiteConnection.ClearAllPools()
adalah solusi terbersih. Sejauh yang saya tahu, tidak tepat untuk memanggil secara manualGC.Collect()
di lingkungan WPF. Meskipun demikian, saya tidak menyadari masalahnya sampai saya meningkatkan keSystem.Data.SQLite
1.0.99.0 pada 3/2016sumber
Mungkin Anda tidak perlu berurusan dengan GC sama sekali. Tolong, periksa apakah semua
sqlite3_prepare
sudah selesai.Untuk masing-masing
sqlite3_prepare
, Anda membutuhkan seorang korespondensqlite3_finalize
.Jika Anda tidak menyelesaikan dengan benar,
sqlite3_close
tidak akan menutup koneksi.sumber
Saya berjuang dengan masalah yang sama. Malu pada saya ... Saya akhirnya menyadari bahwa Reader tidak ditutup. Untuk beberapa alasan saya berpikir bahwa Pembaca akan ditutup saat koneksi terkait ditutup. Jelas, GC.Collect () tidak berhasil untuk saya.
Membungkus Pembaca dengan "menggunakan: pernyataan juga merupakan ide yang bagus. Ini adalah kode tes cepat.
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(); } } }
sumber
Saya menggunakan SQLite 1.0.101.0 dengan EF6 dan mengalami masalah dengan file yang terkunci setelah semua koneksi dan entitas dibuang.
Ini menjadi lebih buruk dengan pembaruan dari EF yang menjaga basis data terkunci setelah mereka selesai. GC.Collect () adalah satu-satunya solusi yang membantu dan saya mulai putus asa.
Dalam keputusasaan, saya mencoba ClearSQLiteCommandConnectionHelper dari Oliver Wickenden (lihat jawabannya tanggal 8 Juli). Fantastis. Semua masalah penguncian hilang! Terima kasih Oliver.
sumber
Menunggu Pengumpul Sampah mungkin tidak merilis database sepanjang waktu dan itu terjadi pada saya. Ketika beberapa jenis Exception terjadi dalam database SQLite misalnya mencoba memasukkan baris dengan nilai yang ada untuk PrimaryKey itu akan menahan file database sampai Anda membuangnya. Kode berikut menangkap pengecualian SQLite dan membatalkan perintah yang bermasalah.
SQLiteCommand insertCommand = connection.CreateCommand(); try { // some insert parameters insertCommand.ExecuteNonQuery(); } catch (SQLiteException exception) { insertCommand.Cancel(); insertCommand.Dispose(); }
Jika Anda tidak menangani pengecualian perintah yang bermasalah daripada Pengumpul Sampah tidak dapat berbuat apa-apa karena ada beberapa pengecualian yang tidak tertangani tentang perintah ini sehingga tidak menjadi sampah. Metode penanganan ini bekerja dengan baik untuk saya dengan menunggu pemulung.
sumber
Ini berfungsi untuk saya tetapi saya perhatikan terkadang file jurnal -wal -shm tidak dihapus ketika proses ditutup. Jika Anda ingin SQLite menghapus file -wal -shm ketika semua koneksi ditutup, koneksi terakhir ditutup HARUS non-readonly. Semoga ini bisa membantu seseorang.
sumber
Jawaban terbaik yang berhasil untuk saya.
sumber