我有一个正在开发的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); } }
答案 0 :(得分:2)
答案 1 :(得分:1)
如果您正在重用update语句,则应在使用后立即调用语句上的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);
}
答案 2 :(得分:1)
看起来你需要让sqlite在杀死你的应用程序之前完成它的当前任务 - SQLITE_Busy意味着"the database file is locked",所以关注the docs here应该让你走上正确的道路。
答案 3 :(得分:1)
您确定在应用程序使用期间为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;
}
}
这有帮助吗?