Tengo problemas para cerrar mi base de datos antes de intentar eliminar el archivo. El código es solo
myconnection.Close();
File.Delete(filename);
Y Delete lanza una excepción de que el archivo todavía está en uso. He vuelto a probar Delete () en el depurador después de unos minutos, por lo que no es un problema de tiempo.
Tengo un código de transacción, pero no se ejecuta en absoluto antes de la llamada Close (). Así que estoy bastante seguro de que no es una transacción abierta. Los comandos sql entre abrir y cerrar son solo selecciones.
ProcMon muestra mi programa y mi antivirus mirando el archivo de la base de datos. No muestra que mi programa libere el archivo db después de close ().
Visual Studio 2010, C #, System.Data.SQLite versión 1.0.77.0, Win7
Vi un error de dos años como este, pero el registro de cambios dice que está arreglado.
¿Hay algo más que pueda comprobar? ¿Hay alguna forma de obtener una lista de los comandos o transacciones abiertos?
Nuevo código de trabajo:
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);
fuente
SQLiteAsyncConnection.ResetPool()
, consulte este problema para obtener más detalles.Respuestas:
Encontré el mismo problema hace un tiempo mientras escribía una capa de abstracción de base de datos para C # y nunca logré averiguar cuál era el problema. Terminé lanzando una excepción cuando intentaste eliminar una base de datos SQLite usando mi biblioteca.
De todos modos, esta tarde lo estaba revisando todo de nuevo y pensé que intentaría averiguar por qué estaba haciendo eso de una vez por todas, así que esto es lo que he encontrado hasta ahora.
Lo que sucede cuando llama
SQLiteConnection.Close()
es que (junto con una serie de comprobaciones y otras cosas)SQLiteConnectionHandle
se elimina el que apunta a la instancia de la base de datos SQLite. Esto se hace mediante una llamada aSQLiteConnectionHandle.Dispose()
, sin embargo, esto en realidad no libera el puntero hasta que el recolector de basura de CLR realiza una recolección de basura. Dado queSQLiteConnectionHandle
anula laCriticalHandle.ReleaseHandle()
función a llamarsqlite3_close_interop()
(a través de otra función), esto no cierra la base de datos.Desde mi punto de vista, esta es una muy mala manera de hacer las cosas, ya que el programador no está realmente seguro de cuándo se cierra la base de datos, pero así es como se ha hecho, así que supongo que tenemos que vivir con eso por ahora, o comprometernos. algunos cambios en System.Data.SQLite. Cualquier voluntario puede hacerlo, desafortunadamente no tengo tiempo para hacerlo antes del próximo año.
TL; DR La solución es forzar un GC después de su llamada ay
SQLiteConnection.Close()
antes de su llamada aFile.Delete()
.Aquí está el código de ejemplo:
Buena suerte con eso y espero que ayude
fuente
Simplemente
GC.Collect()
no funcionó para mí.Tuve que agregar
GC.WaitForPendingFinalizers()
despuésGC.Collect()
para continuar con la eliminación del archivo.fuente
GC.Collect()
simplemente inicia una recolección de basura que es asincrónica, por lo que para asegurarse de que todo se haya limpiado, debe esperar explícitamente.En mi caso, estaba creando
SQLiteCommand
objetos sin eliminarlos explícitamente.Envolví mi comando en una
using
declaración y solucionó mi problema.Entonces también es mucho más fácil ejecutar comandos.
fuente
Tuve un problema similar, aunque la solución del recolector de basura no lo solucionó.
La eliminación de objetos
SQLiteCommand
ySQLiteDataReader
objetos después de su uso me salvó de usar el recolector de basura.fuente
SQLiteCommand
incluso si recicla unaSQLiteCommand
variable más adelante.command.Dispose();
a todos losSQLiteCommand
que se ejecutaron..Dispose()
) otros objetos como SQLiteTransaction, si tiene alguno.Lo siguiente funcionó para mí:
Más información : SQLite agrupa las conexiones para mejorar el rendimiento, lo que significa que cuando llamas al método Close en un objeto de conexión, es posible que la conexión a la base de datos todavía esté activa (en segundo plano) para que el siguiente método Open sea más rápido. ya no desea una nueva conexión, llamar a ClearAllPools cierra todas las conexiones que están vivas en segundo plano y se liberan los identificadores de archivo para el archivo db. Luego, el archivo db puede ser eliminado, eliminado o utilizado por otro proceso.
fuente
SQLiteConnectionPool.Shared.Reset()
. Esto cerrará todas las conexiones abiertas. En particular, esta es una solución si usaSQLiteAsyncConnection
que no tiene unClose()
método.Estaba teniendo un problema similar, probé la solución con
GC.Collect
pero, como se señaló, puede pasar mucho tiempo antes de que el archivo no se bloquee.Encontré una solución alternativa que implica la eliminación de los
SQLiteCommand
s subyacentes en los TableAdapters; consulte esta respuesta para obtener información adicional.fuente
Prueba esto ... este prueba todos los códigos anteriores ... funcionó para mí
Espero que ayude
fuente
He tenido el mismo problema con EF y
System.Data.Sqlite
.Para mí, encontré
SQLiteConnection.ClearAllPools()
yGC.Collect()
reduciría la frecuencia con la que se produciría el bloqueo de archivos, pero aún así sucedía ocasionalmente (alrededor del 1% del tiempo).He estado investigando y parece ser que algunos
SQLiteCommand
mensajes de correo electrónico que crea EF no se eliminan y aún tienen su propiedad Connection establecida en la conexión cerrada. Intenté eliminarlos, pero Entity Framework arrojaría una excepción durante la siguienteDbContext
lectura; parece que EF a veces todavía los usa después de que se cierra la conexión.Mi solución fue asegurarme de que la propiedad Connection esté configurada
Null
cuando la conexión se cierre en estosSQLiteCommand
s. Esto parece ser suficiente para liberar el bloqueo del archivo. He estado probando el siguiente código y no he visto ningún problema de bloqueo de archivos después de varios miles de pruebas:Para usarlo, simplemente llame
ClearSQLiteCommandConnectionHelper.Initialise();
al inicio de la carga de la aplicación. Esto entonces mantendrá una lista de comandos activos y establecerá su ConexiónNull
cuando apunten a una conexión que está cerrada.fuente
Utilizar
GC.WaitForPendingFinalizers()
Ejemplo:
fuente
Tuvo un problema similar. Llamar al recolector de basura no me ayudó. Después encontré una manera de resolver el problema
El autor también escribió que hizo consultas SELECT a esa base de datos antes de intentar eliminarla. Yo tengo la misma situación.
Tengo el siguiente código:
Además, no necesito cerrar la conexión de la base de datos y llamar a Garbage Collector. Todo lo que tenía que hacer era cerrar el lector que se creó al ejecutar la consulta SELECT
fuente
Creo que la llamada a
SQLite.SQLiteConnection.ClearAllPools()
es la solución más limpia. Hasta donde yo sé, no es apropiado llamar manualmenteGC.Collect()
en el entorno WPF. Aunque, no noté el problema hasta que actualicé aSystem.Data.SQLite
1.0.99.0 en 3/2016fuente
Quizás no necesites lidiar con GC en absoluto. Por favor, compruebe si todo
sqlite3_prepare
está finalizado.Para cada uno
sqlite3_prepare
, necesita un corresponsalsqlite3_finalize
.Si no finaliza correctamente,
sqlite3_close
no cerrará la conexión.fuente
Estaba luchando con un problema similar. Qué vergüenza ... Finalmente me di cuenta de que Reader no estaba cerrado. Por alguna razón, estaba pensando que el Reader se cerrará cuando se cierre la conexión correspondiente. Obviamente, GC.Collect () no funcionó para mí.
También es una buena idea envolver el lector con la declaración "using:". Aquí hay un código de prueba rápido.
fuente
Estaba usando SQLite 1.0.101.0 con EF6 y tenía problemas con el archivo bloqueado después de eliminar todas las conexiones y entidades.
Esto empeoró con las actualizaciones de EF que mantenían la base de datos bloqueada después de que se habían completado. GC.Collect () fue la única solución que ayudó y estaba comenzando a desesperarme.
Desesperado, probé ClearSQLiteCommandConnectionHelper de Oliver Wickenden (vea su respuesta del 8 de julio). Fantástico. ¡Todos los problemas de bloqueo desaparecieron! Gracias Oliver.
fuente
Es posible que esperar al recolector de basura no libere la base de datos todo el tiempo y eso me sucedió. Cuando se produce algún tipo de excepción en la base de datos SQLite, por ejemplo, al intentar insertar una fila con un valor existente para PrimaryKey, se mantendrá el archivo de la base de datos hasta que lo deseche. El siguiente código detecta la excepción SQLite y cancela el comando problemático.
Si no maneja las excepciones de comandos problemáticos, Garbage Collector no puede hacer nada al respecto porque hay algunas excepciones no manejadas sobre estos comandos, por lo que no son basura. Este método de manejo funcionó bien para mí esperando al recolector de basura.
fuente
Esto funciona para mí, pero noté que a veces los archivos de diario -wal -shm no se eliminan cuando se cierra el proceso. Si desea que SQLite elimine los archivos -wal -shm cuando todas las conexiones estén cerradas, la última conexión cerrada DEBE SER de no solo lectura. Espero que esto ayude a alguien.
fuente
La mejor respuesta que funcionó para mí.
fuente