Некоторые изменения в базе данных SQLite не сохраняются после закрытия и повторного запуска приложения - PullRequest
1 голос
/ 13 мая 2009

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

За время существования приложения я запускаю несколько операторов INSERT и UPDATE. Однако по какой-то причине мои UPDATE операторы не сохраняются должным образом, как только приложение закрывается и затем перезапускается. Я правильно звоню sqlite3_prepare_v2, sqlite3_step и sqlite3_finalize, поэтому я уверен, что транзакции должны быть завершены. Я добавил точки останова для всех этих трех функций, и все они в порядке, и все возвращают правильные значения.

Когда я закрываю приложение после обновления и заглядываю в каталог документов, я вижу другой файл базы данных с -journal после него. Означает ли это, что что-то не работает должным образом с точки зрения транзакций?

Я также заметил, что в моем методе applicationWillTerminate:, когда я закрываю соединение с помощью sqlite3_close(), он возвращает SQLITE_BUSY. Почему это может быть?

Я боролась целый день, поэтому я очень надеюсь, что кто-то может указать мне правильное направление!

Вот мой код для выполнения запросов на обновление:

// Update statement
sqlite3_stmt *stmt;
char *query = "UPDATE records SET fielda = ? WHERE pkfield = ?;";
if (sqlite3_prepare_v2(database, query, -1, &stmt, nil) == SQLITE_OK &&

   // Bind
   sqlite3_bind_text(stmt, 1, [myNSStringVar UTF8String], -1, nil) == SQLITE_OK &&
   sqlite3_bind_int(stmt, 2, recordID) == SQLITE_OK) {

   // Execute
   int ret = sqlite3_step(stmt);
   if (ret == SQLITE_DONE) {
      sqlite3_finalize(stmt);
   }
}

Ответы [ 4 ]

2 голосов
/ 13 мая 2009

Ах ... Я понял это! Одно из моих неясных окончательных утверждений так и не было достигнуто! Поскольку это был только оператор SELECT, я не проверял его, потому что он не имеет никакого отношения к каким-либо манипуляциям с данными или транзакциям! Это день развития из окна! Но я не сделаю эту ошибку снова!

Спасибо за вашу помощь, ребята!

1 голос
/ 13 мая 2009

Похоже, вам нужно дать sqlite завершить свои текущие задачи перед тем, как убить ваше приложение - SQLITE_Busy означает, что "файл базы данных заблокирован" , поэтому следуйте документации здесь должен установить вас на правильный путь.

1 голос
/ 13 мая 2009

Вы уверены, что сохранение большого количества материала в вашей базе данных SQLite во время использования приложения является лучшим для производительности?

Я склонен хранить изменения и т. Д. В NSMutableArray во время выполнения, устанавливая «грязный» флаг в YES каждый раз, когда объект обновляется.

Затем в моем методе applicationWillTerminate я вызываю следующее:

[todos makeObjectsPerformSelector:@selector(dehydrate)];

Мой метод «обезвоживания» (основанный на собственном руководстве Apple по работе с базами данных SQLite) по существу таков:

- (void) dehydrate {
if (dirty) {
    if (dehydrate_statement == nil) {
        const char *sql = "UPDATE todo SET text=?,priority=?,complete=?,detail=? WHERE pk=?";
        if (sqlite3_prepare_v2(database,sql,-1,&dehydrate_statement,NULL) != SQLITE_OK) {
            NSAssert1(0,@"Error: failed to prepare statement with message '%s'.",sqlite3_errmsg(database));
        }
    }

    sqlite3_bind_int(dehydrate_statement, 5, self.primaryKey);
    sqlite3_bind_text(dehydrate_statement, 4, [self.detail UTF8String],-1,SQLITE_TRANSIENT);
    sqlite3_bind_int(dehydrate_statement, 3, self.status);
    sqlite3_bind_int(dehydrate_statement, 2, self.priority);
    sqlite3_bind_text(dehydrate_statement, 1, [self.text UTF8String],-1,SQLITE_TRANSIENT);
    int success = sqlite3_step(dehydrate_statement);

    if (success != SQLITE_DONE) {
        NSAssert1(0,@"Error: failed to save changes with message '%s'.", sqlite3_errmsg(database));
    }

    sqlite3_reset(dehydrate_statement);
    dirty = NO;
    }
}

Помогает ли это вообще?

1 голос
/ 13 мая 2009

Если вы повторно используете операторы обновления, вы должны вызывать sqlite3_reset () в операторе сразу после использования, также может потребоваться вызов sqlite3_clear_bindings (), чтобы убедиться, что назначенные параметры сброшены. Затем вы должны вызывать sqlite3_finalize только при очистке. Это может быть вашей проблемой, потому что, если оператор все еще выполняется, и вы вызываете sqlite3_finalize для него, то выполнение будет прервано. Тем не менее, вы, скорее всего, должны повторно использовать заявления для эффективности, если вы этого еще не сделали. Для меня это работает так:

static sqlite3_stmt *update_statement = nil;

-(void)performUpdateOnRow: (NSInteger)primaryKey {

    if (update_statement == nil){
        const char *sql = "UPDATE foo SET bar=?,baz=? WHERE pk=?";
        if( sqlite3_prepare_v2(database, sql, -1, &update_statement, NULL) != SQLITE_OK ){
                // Insert some serious error handling here!
        }
    }
    sqlite3_bind_text(update_statement, 1, @"first", -1,SQLITE_TRANSIENT);
    sqlite3_bind_text(update_statement, 2, @"second", -1,SQLITE_TRANSIENT); 
    sqlite3_bind_int(update_statement, 3, primaryKey);

    sqlite3_step(update_statement);
    sqlite3_reset(update_statement);

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...