У меня проблема с закрытием базы данных перед попыткой удалить файл. Код просто
myconnection.Close();
File.Delete(filename);
И Delete выдает исключение, что файл все еще используется. Я повторно попробовал Delete () в отладчике через несколько минут, так что это не проблема времени.
У меня есть код транзакции, но он вообще не запускается до вызова Close (). Так что я почти уверен, что это не открытая сделка. Команды sql между открытием и закрытием - это просто выбор.
ProcMon показывает мою программу и мой антивирус, просматривая файл базы данных. Это не показывает, что моя программа освобождает файл db после close ().
Visual Studio 2010, C #, System.Data.SQLite версии 1.0.77.0, Win7
Я видел ошибку двухлетней давности, но в журнале изменений сказано, что она исправлена.
Могу я еще что-нибудь проверить? Есть ли способ получить список открытых команд или транзакций?
Новый рабочий код:
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);
источник
SQLiteAsyncConnection.ResetPool()
, подробности см. В этой проблеме .Ответы:
Некоторое время назад столкнулся с той же проблемой при написании уровня абстракции БД для C #, и я никогда не удосужился выяснить, в чем проблема. Я только что выбросил исключение, когда вы попытались удалить базу данных SQLite с помощью моей библиотеки.
Во всяком случае, сегодня днем я просматривал все это снова и решил, что попытаюсь выяснить, почему он делает это, раз и навсегда, так что вот что я нашел до сих пор.
Когда вы вызываете
SQLiteConnection.Close()
, то (наряду с рядом проверок и прочего) удаляется объектSQLiteConnectionHandle
, указывающий на экземпляр базы данных SQLite. Это делается с помощью вызоваSQLiteConnectionHandle.Dispose()
, однако на самом деле это не освобождает указатель, пока сборщик мусора CLR не выполнит некоторую сборку мусора. ПосколькуSQLiteConnectionHandle
переопределяетCriticalHandle.ReleaseHandle()
функцию для вызоваsqlite3_close_interop()
(через другую функцию), это не закрывает базу данных.С моей точки зрения, это очень плохой способ делать что-то, поскольку программист на самом деле не уверен, когда база данных закрывается, но именно так это было сделано, поэтому я думаю, что мы должны жить с этим сейчас, или зафиксировать несколько изменений в System.Data.SQLite. Любые волонтеры могут это сделать, но, к сожалению, у меня нет времени сделать это до следующего года.
TL; DR Решение состоит в том, чтобы принудительно выполнить сборку мусора после вашего вызова
SQLiteConnection.Close()
и до вашего вызоваFile.Delete()
.Вот пример кода:
Удачи с этим, и я надеюсь, что это поможет
источник
Просто
GC.Collect()
у меня не сработало.Мне пришлось добавить
GC.WaitForPendingFinalizers()
послеGC.Collect()
, чтобы продолжить удаление файла.источник
GC.Collect()
просто запускается асинхронная сборка мусора, поэтому, чтобы убедиться, что все было очищено, вам нужно явно дождаться этого.В моем случае я создавал
SQLiteCommand
объекты, не удаляя их явно.Я заключил свою команду в
using
оператор, и это устранило мою проблему.Тогда намного проще выполнять команды.
источник
Была аналогичная проблема, хотя решение для сборщика мусора не исправило ее.
Обнаружение утилизации предметов
SQLiteCommand
иSQLiteDataReader
предметов после использования избавило меня от использования сборщика мусора.источник
SQLiteCommand
даже еслиSQLiteCommand
позже вы повторно используете переменную.command.Dispose();
все,SQLiteCommand
что было выполнено..Dispose()
) другие объекты, такие как SQLiteTransaction, если они у вас есть.Для меня сработало следующее:
Дополнительная информация : SQLite объединяет подключения в пул для повышения производительности. Это означает, что при вызове метода Close для объекта подключения подключение к базе данных может быть активным (в фоновом режиме), поэтому следующий метод Open станет быстрее. вам больше не нужно новое соединение, вызов ClearAllPools закрывает все соединения, которые активны в фоновом режиме, и дескрипторы файлов для файла db освобождаются. Затем файл db может быть удален, удален или использован другим процессом.
источник
SQLiteConnectionPool.Shared.Reset()
. Это закроет все открытые соединения. В частности, это решение, если вы используетеSQLiteAsyncConnection
не имеющийClose()
метода.У меня была аналогичная проблема, я пробовал решение,
GC.Collect
но, как уже отмечалось, может пройти много времени, прежде чем файл станет незаблокированным.Я нашел альтернативное решение, которое включает удаление базовых
SQLiteCommand
s в TableAdapters, см. Этот ответ для получения дополнительной информации.источник
У меня была такая же проблема с EF и
System.Data.Sqlite
.Что касается меня, я обнаружил
SQLiteConnection.ClearAllPools()
иGC.Collect()
уменьшил частоту блокирования файлов, но это все равно время от времени происходило (примерно в 1% случаев).Я исследовал, и кажется, что некоторые,
SQLiteCommand
которые создает EF, не удаляются, и для их свойства Connection все еще установлено закрытое соединение. Я попытался избавиться от них, но Entity Framework тогда выдает исключение во время следующегоDbContext
чтения - кажется, EF иногда все еще использует их после закрытия соединения.Мое решение заключалось в том, чтобы установить для свойства Connection значение,
Null
когда соединение закрывается на этихSQLiteCommand
s. Кажется, этого достаточно, чтобы снять блокировку файла. Я тестировал приведенный ниже код и не видел проблем с блокировкой файлов после нескольких тысяч тестов:Чтобы использовать, просто позвоните
ClearSQLiteCommandConnectionHelper.Initialise();
в начале загрузки приложения. После этого будет сохранен список активных команд, и для них будет установлено значение Connection,Null
когда они будут указывать на закрытое соединение.источник
Попробуйте это ... этот пытается все вышеперечисленные коды ... сработал для меня
надеюсь, это поможет
источник
Использовать
GC.WaitForPendingFinalizers()
Пример:
источник
Была аналогичная проблема. Вызов сборщика мусора мне не помог. LAter я нашел способ решить проблему
Автор также написал, что он делал запросы SELECT к этой базе данных, прежде чем пытаться удалить ее. У меня такая же ситуация.
У меня такой код:
Кроме того, мне не нужно закрывать соединение с базой данных и вызывать сборщик мусора. Все, что мне нужно было сделать, это закрыть ридер, созданный при выполнении запроса SELECT.
источник
Я считаю, что призыв
SQLite.SQLiteConnection.ClearAllPools()
- самое чистое решение. Насколько я знаю, вызывать вручнуюGC.Collect()
в среде WPF нецелесообразно. Хотя я не заметил проблемы, пока неSystem.Data.SQLite
обновился до 1.0.99.0 в 3/2016.источник
Возможно, вам вообще не нужно иметь дело с GC. Пожалуйста, проверьте, все ли
sqlite3_prepare
завершено.Для каждого
sqlite3_prepare
нужен корреспондентsqlite3_finalize
.Если вы не завершите правильно, соединение
sqlite3_close
не закроется.источник
Я боролся с аналогичной проблемой. Позор мне ... Я наконец понял, что Reader не закрывается. Я почему-то подумал, что Ридер закроется при закрытии соответствующего соединения. Очевидно, GC.Collect () у меня не работал.
Обернуть Reader с помощью оператора using: также является хорошей идеей. Вот код для быстрой проверки.
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(); } } }
источник
Я использовал SQLite 1.0.101.0 с EF6, и у меня возникли проблемы с блокировкой файла после удаления всех подключений и объектов.
Ситуация усугублялась тем, что обновления из EF блокировали базу данных после их завершения. GC.Collect () был единственным решением, которое помогло, и я начинал отчаиваться.
В отчаянии я попробовал ClearSQLiteCommandConnectionHelper Оливера Викендена (см. Его ответ от 8 июля). Фантастика. Все проблемы с блокировкой исчезли! Спасибо Оливер.
источник
Ожидание сборщика мусора может не освобождать базу данных все время, и это случилось со мной. Когда какой-либо тип исключения возникает в базе данных SQLite, например, при попытке вставить строку с существующим значением для PrimaryKey, он будет удерживать файл базы данных, пока вы его не удалите. Следующий код перехватывает исключение SQLite и отменяет проблемную команду.
SQLiteCommand insertCommand = connection.CreateCommand(); try { // some insert parameters insertCommand.ExecuteNonQuery(); } catch (SQLiteException exception) { insertCommand.Cancel(); insertCommand.Dispose(); }
Если вы не обрабатываете исключения проблемных команд, то сборщик мусора ничего не сможет с ними поделать, потому что для этих команд есть необработанные исключения, поэтому они не являются мусором. Этот метод обработки хорошо работал у меня с ожиданием сборщика мусора.
источник
Это работает для меня, но я заметил, что иногда файлы журнала -wal -shm не удаляются при закрытии процесса. Если вы хотите, чтобы SQLite удалял файлы -wal -shm, когда все соединения закрыты, последнее закрытое соединение ДОЛЖНО БЫТЬ не доступным только для чтения. Надеюсь, это кому-то поможет.
источник
Лучший ответ, который сработал для меня.
источник