Tengo un sistema que se basa en la base de datos SQLite. Cada cliente tiene una base de datos local, y de vez en cuando la actualización llega desde el servidor principal, solo un pequeño archivo .db delta. La tarea es fusionarse a la base de datos local con el archivo delta, el esquema es idéntico en ambos.Error al separar la base de datos SQLite - la base de datos está bloqueada
Para la gestión de mi base de datos utilizo fmdb wrapper que se puede encontrar here. En el hilo principal, mantengo abierta la conexión a la base de datos local. El archivo delta llega en segundo plano, y quiero hacer la fusión en segundo plano para evitar que se congele cualquier interfaz de usuario que esto pueda causar.
En cuanto a la fusión, la única opción que encontré es adjuntar la base de datos delta a la base de datos local, luego insertar/actualizar las filas y finalmente separar el delta. Esto no funciona tan bien como esperaba.
Descripción Código:
- El onDeltaGenerated método se invoca en un subproceso en segundo plano cada vez que la base de datos de delta está listo para ser procesado (llega desde el servidor y se guarda en la ubicación legible).
- deltaDBPath es la ubicación absoluta de la base de datos delta en el sistema de archivos.
- db referencias variables abren la conexión FMDataBase.
Código:
- (void)onDeltaGenerated:(NSNotification*)n {
NSString* deltaDBPath = [[n userInfo] objectForKey:@"deltaPath"];
@synchronized(db) {
[db executeUpdate:@"ATTACH DATABASE ? AS delta", deltaDBPath];
if ([db hadError]) {
NSLog(@" ****ERROR*** %d: %@", [db lastErrorCode], [db lastErrorMessage]);
} else {
NSLog(@"Delta attached from %@", deltaDBPath);
}
[db beginTransaction];
BOOL update1 = NO;
BOOL update2 = NO;
BOOL transaction = NO;
update1 = [db executeUpdate:@"INSERT OR REPLACE INTO equipment SELECT * FROM delta.equipment"];
if (!update1) {
NSLog(@" *** ERROR *** update 1 failed!");
NSLog(@" ****ERROR*** %d: %@", [db lastErrorCode], [db lastErrorMessage]);
}
update2 = [db executeUpdate:@"INSERT OR REPLACE INTO equipmentExt SELECT * FROM delta.equipmentExt"];
if (!update2) {
NSLog(@" *** ERROR *** update 2 failed!");
NSLog(@" ****ERROR*** %d: %@", [db lastErrorCode], [db lastErrorMessage]);
}
transaction = [db commit];
if (!transaction) {
NSLog(@" *** ERROR *** transaction failed!");
NSLog(@" ****ERROR*** %d: %@", [db lastErrorCode], [db lastErrorMessage]);
}
[db executeUpdate:@"DETACH DATABASE delta"];
if ([db hadError]) {
NSLog(@" ****ERROR*** %d: %@", [db lastErrorCode], [db lastErrorMessage]);
} else {
NSLog(@"Delta detached");
}
}
}
Después de este método se invoca por primera vez, todo parece estar bien hasta que intento de separar la base de datos. Cuando trato de hacerlo, me sale el siguiente error:
2012-01-11 12:08:52.106 DBApp[1415:11507] Error calling sqlite3_step (1: SQL logic error or missing database) SQLITE_ERROR
2012-01-11 12:08:52.107 DBApp[1415:11507] DB Query: DETACH delta
2012-01-11 12:08:52.107 DBApp[1415:11507] ****ERROR*** 1: database delta is locked
También probé a la misma, pero sin poner inserta en la transacción, el resultado es idéntico. Otra cosa fue eliminar la cláusula @synchronized, pero tampoco suerte. Mi suposición es que si falla al intentar acceder a la conexión de la base de datos local desde el hilo de fondo, ¿pero cómo se las arregla para adjuntar e insertar? Cualquier ayuda apreciada.
Editar
I trasladó el código para el hilo principal, por lo que el DB es ahora acceder desde el hilo principal solamente. El problema permanece
Edit2
Ok, así que después de intentar todo, me di por vencido en esto por un momento y luego regresó cuando la primera respuesta apareció aquí. Sorprendentemente, todo parece funcionar bien ahora, por lo que mi código debe ser correcto. Sospecho que este fue el problema con diferentes hilos que bloquean el archivo, ya que utilicé XCode, SQLiteDatabaseBrowser y mi aplicación para abrir la base de datos. Aunque el lsof mostró que el archivo no estaba bloqueado, creo que era incorrecto y que XCode o SQLiteDatabaseBrowser lo estaban bloqueando. Considero que el problema está resuelto, y la lección que se extrajo de esto no es tanto empujarlo y planificar mejor la depuración la próxima vez.
¿Todos los métodos transactionUpdate y execute devuelven SÍ? – Mark
Sí, lo hacen. Además, verifiqué si tal vez algún otro proceso está bloqueando la base de datos (utilicé el fusor), pero este no es el caso. Hasta ahora he estado probando en el simulador, pero ahora veo que tampoco funciona en el iPod Touch, pero falla con el mismo error. – lawicko
Solo marcando: su base de datos no está almacenada en una unidad montada en NFS, ¿o sí? – jogojapan