Ошибка при отключении базы данных SQLite - база данных заблокирована

У меня есть система, основанная на базе данных SQLite. У каждого клиента есть локальная база данных, и время от времени обновление приходит с главного сервера, только небольшой файл дельты .db. Задача - слить в локальную базу данных дельта-файл, в обоих схема идентична.

Для управления базой данных я использую оболочку fmdb, которую можно найти здесь . В основном потоке я поддерживаю соединение с локальной базой данных. Дельта-файл поступает в фоновом режиме, и я хочу выполнить слияние в фоновом режиме, чтобы избежать зависаний пользовательского интерфейса, которые это может вызвать.

Что касается самого слияния, единственный вариант, который я нашел, - это присоединить базу данных дельты к локальной базе данных, затем вставить / обновить строки и, наконец, отсоединить дельту. Это не работает так гладко, как я ожидал.

Описание кода:

  • Метод onDeltaGenerated вызывается в фоновом потоке всякий раз, когда база данных дельты готова к обработке (поступает с сервера и сохраняется в доступном для чтения месте).
  • deltaDBPath - это абсолютное расположение базы данных дельты в файловой системе.
  • Переменная db ссылается на открытое соединение FMDataBase.

Код:

- (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");
    }
}

}

После первого вызова этого метода все в порядке, пока я не попытаюсь отсоединить базу данных. Когда я пытаюсь это сделать, я получаю следующую ошибку:

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

Я тоже пытался сделать то же самое, но без вставки в транзакцию результат идентичный. Другое дело было удалить предложение @synchronized, но тоже не повезло. Я предполагаю, что если не удается получить доступ к подключению к локальной базе данных из фонового потока, но тогда как же ему удается подключиться и вставить? Любая помощь приветствуется.

Edit

Я переместил код в основной поток, поэтому теперь доступ к базе данных осуществляется только из основного потока. Проблема остается.

Edit2

Итак, попробовав все, я на мгновение отказался от этого, а затем вернулся, когда здесь появился первый ответ. Удивительно, но сейчас, похоже, все работает нормально, поэтому мой код должен быть правильным.Я подозреваю, что это была проблема с разными потоками, блокирующими файл, поскольку я использовал XCode, SQLiteDatabaseBrowser и свое приложение для открытия базы данных. Несмотря на то, что lsof показал, что файл не был заблокирован, я думаю, что это было неправильно, и либо XCode, либо SQLiteDatabaseBrowser блокировали его. Я считаю, что проблема решена, и урок, извлеченный из этого, состоит в том, чтобы не зацикливаться на lsof так много, а также лучше спланировать отладку в следующий раз.

6
задан lawicko 5 March 2012 в 11:54
поделиться