分离SQLite数据库时出错 - 数据库已锁定

时间:2012-01-11 13:11:17

标签: objective-c multithreading sqlite fmdb

我有一个基于SQLite数据库的系统。每个客户端都有一个本地数据库,并且偶尔从主服务器到达一个小的delta .db文件。任务是使用增量文件合并到本地数据库,两者中的模式相同。

对于我的数据库管理,我使用可以找到的here的fmdb包装器。在主线程中,我保持与本地数据库的连接打开。增量文件到达后台,我想在后台进行合并,以避免任何用户界面冻结,这可能导致。

至于合并本身,我发现的唯一选择是将delta数据库附加到本地数据库,然后插入/更新行,最后分离delta。这不像我预期的那样顺利。

代码说明:

  • 只要delta数据库准备好处理(从服务器到达并保存在可读位置),就会在后台线程中调用 onDeltaGenerated 方法。
  • deltaDBPath 是文件系统中delta数据库的绝对位置。
  • 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子句,但也没有运气。我的猜测是,如果尝试从后台线程访问本地数据库连接失败,但那么它如何设法附加和插入?任何帮助表示赞赏。

修改

我将代码移动到主线程,因此现在只能从主线程访问db。问题依然存在。

EDIT2

好的,所以在尝试了一切之后,我放弃了一会儿,然后在第一个答案出现在这里时又回来了。令人惊讶的是,现在一切似乎都运行正常,所以我的代码必须正确。我怀疑这是锁定文件的不同线程的问题,因为我使用XCode,SQLiteDatabaseBrowser和我的应用程序来打开数据库。即使 lsof 显示该文件未被锁定,我认为这是错误的,XCode或SQLiteDatabaseBrowser都将其锁定。我认为这个问题已经解决了,从中吸取的教训并不是如此强烈,而是下次还要更好地规划调试。

4 个答案:

答案 0 :(得分:1)

只是检查 - NSLog(@"Delta attached from %@", deltaDBPath);是否成功打印,然后您描述的错误会发生?


线Error calling sqlite3_step (1: SQL logic error or missing database) SQLITE_ERROR可能是最有趣的一点。

稍微使用谷歌搜索后,出现的一个问题是数据库文件可能无法写入。 http://www.iphonedevsdk.com/forum/iphone-sdk-development/20142-problem-insert-fmdb.html

如果您要更新的主数据库位于应用程序包中,则不允许对其进行修改 - 您应首先复制到Documents或其他可写目录。


当您尝试分离时是否实际发生了错误,或者当您尝试执行INSERT OR REPLACE事务时实际发生了错误?

你应该在这些陈述之后加上另一个if ([db hadError]) {…来确定吗?

答案 1 :(得分:1)

你已经

了吗?
[db open];

别处?

答案 2 :(得分:1)

您确定将所有查询重置为db吗? 确保你拨打sqlite3_reset(stmt)电话。

答案 3 :(得分:0)

这是一个让我知道的(你知道在哪里): 在构建一个需要额外ATTACHed数据库的新功能(顺便说一句,在.NET中)时,我正在进行彻底的测试(看起来太多了)。 所以我

var i = query.ExecuteNonQuery("ATTACH DATABASE @FilePath AS `MergeDestination`;", fullPath);
FakeCallThatDoesNothing()
var i = query.ExecuteNonQuery("DETACH DATABASE `MergeDestination`;");
显然,它没有足够的时间来进行附件,并导致很多人头疼。