Estoy realizando una gran cantidad de INSERTOS en una base de datos SQLite. Estoy usando solo un hilo. Loteo las escrituras para mejorar el rendimiento y tener un poco de seguridad en caso de un bloqueo. Básicamente guardo en la memoria caché un montón de datos y luego, cuando lo considero apropiado, recorro todos esos datos y realizo los INSERTOS. El código para esto se muestra a continuación:El archivo de base de datos está inexplicablemente bloqueado durante la confirmación SQLite
public void Commit()
{
using (SQLiteConnection conn = new SQLiteConnection(this.connString))
{
conn.Open();
using (SQLiteTransaction trans = conn.BeginTransaction())
{
using (SQLiteCommand command = conn.CreateCommand())
{
command.CommandText = "INSERT OR IGNORE INTO [MY_TABLE] (col1, col2) VALUES (?,?)";
command.Parameters.Add(this.col1Param);
command.Parameters.Add(this.col2Param);
foreach (Data o in this.dataTemp)
{
this.col1Param.Value = o.Col1Prop;
this. col2Param.Value = o.Col2Prop;
command.ExecuteNonQuery();
}
}
this.TryHandleCommit(trans);
}
conn.Close();
}
}
ahora emplean el siguiente truco para conseguir la cosa que finalmente funciona:
private void TryHandleCommit(SQLiteTransaction trans)
{
try
{
trans.Commit();
}
catch (Exception e)
{
Console.WriteLine("Trying again...");
this.TryHandleCommit(trans);
}
}
Creo mi DB de este modo:
public DataBase(String path)
{
//build connection string
SQLiteConnectionStringBuilder connString = new SQLiteConnectionStringBuilder();
connString.DataSource = path;
connString.Version = 3;
connString.DefaultTimeout = 5;
connString.JournalMode = SQLiteJournalModeEnum.Persist;
connString.UseUTF16Encoding = true;
using (connection = new SQLiteConnection(connString.ToString()))
{
//check for existence of db
FileInfo f = new FileInfo(path);
if (!f.Exists) //build new blank db
{
SQLiteConnection.CreateFile(path);
connection.Open();
using (SQLiteTransaction trans = connection.BeginTransaction())
{
using (SQLiteCommand command = connection.CreateCommand())
{
command.CommandText = DataBase.CREATE_MATCHES;
command.ExecuteNonQuery();
command.CommandText = DataBase.CREATE_STRING_DATA;
command.ExecuteNonQuery();
//TODO add logging
}
trans.Commit();
}
connection.Close();
}
}
}
Luego exporto la cadena de conexión y la uso para obtener nuevas conexiones en diferentes partes del programa.
En intervalos aparentemente aleatorios, aunque a una velocidad demasiado grande como para ignorar o solucionar este problema, me sale SQLiteException sin gestionar: el archivo de la base de datos está bloqueado. Esto ocurre cuando intento comprometer la transacción. No parece haber errores antes de eso. Esto no significa siempre suceder. A veces todo funciona sin problemas.
- No se están realizando lecturas en estos archivos antes de que finalicen las confirmaciones.
- Tengo el último binario de SQLite.
- Estoy compilando para .NET 2.0.
- Estoy usando VS 2008.
- El db es un archivo local.
- Toda esta actividad se encapsula dentro de un hilo/proceso.
- La protección contra virus está desactivada (aunque creo que eso solo era relevante si se conectaba a través de una red).
- Según el post de escocés He implementado los siguientes cambios:
- Modo Diario configurar para que persistan
- archivos de base de datos almacenada en C: \ Docs + Settings \ ApplicationData través
System.Windows.Forms.Application.AppData
ventanas llaman - Sin excepción interna
- Presenciado en dos máquinas distintas (aunque hardware y software muy similares)
- Ejecutamos Process Monitor, no hay procesos externos que se adjuntan a los archivos de la base de datos. Definitivamente el problema está en mi código ...
¿Alguien tiene alguna idea de lo que está pasando aquí?
Sé que acaba de caer un lío de código, pero he estado tratando de resolver esto por demasiado tiempo. ¡Mi agradecimiento a cualquiera que llegue al final de esta pregunta!
Brian
ACTUALIZACIONES:
, gracias por las sugerencias hasta ahora! Implementé muchos de los cambios sugeridos.Siento que nos estamos acercando a la respuesta ... sin embargo ...
¡El código anterior funciona técnicamente, pero no es determinante! No está garantizado hacer nada aparte de girar en neutral para siempre. En la práctica, parece funcionar en algún lugar entre la primera y la décima iteración. Si hago un lote de mis compromisos a un intervalo razonable, el daño se mitigará, pero realmente no quiero dejar las cosas en este estado ...
¡Más sugerencias bienvenidas!
Aunque no desea tener confirmaciones más pequeñas, ¿sigue apareciendo el problema cuando se mueve begin tran y commit tran en el batch interno? – pjp