【问题标题】:Error when detaching SQLite database - database is locked分离 SQLite 数据库时出错 - 数据库已锁定
【发布时间】:2012-02-07 20:13:12
【问题描述】:

我有一个基于 SQLite 数据库的系统。每个客户端都有一个本地数据库,有时更新会从主服务器到达,只是一个小的 delta .db 文件。任务是使用 delta 文件合并到本地数据库,两者的架构是相同的。

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

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

代码说明:

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

编辑

我将代码移至主线程,因此现在只能从主线程访问数据库。问题依然存在。

编辑2

好的,所以在尝试了一切之后,我暂时放弃了这个,然后当第一个答案出现在这里时又回来了。令人惊讶的是,现在一切似乎都运行良好,所以我的代码一定是正确的。我怀疑这是不同线程锁定文件的问题,因为我使用 XCode、SQLiteDatabaseBrowser 和我的应用程序打开数据库。即使 lsof 显示文件没有被锁定,我认为这是错误的,XCode 或 SQLiteDatabaseBrowser 正在锁定它。我认为问题已经解决了,从中吸取的教训是不要太推lsof,并且下次更好地计划调试。

【问题讨论】:

  • transaction和executeUpdate方法都返回YES吗?
  • 是的,他们有。此外,我检查了是否有其他进程正在锁定数据库(我使用了 fuser),但事实并非如此。到目前为止,我一直在 sim 上进行测试,但现在我发现它在 iPod Touch 上也不起作用,并出现同样的错误。
  • 只是检查:您的数据库没有存储在 NFS 安装的驱动器上,或者是吗?
  • 不行。主数据库在应用程序包中,然后移至 Documents。 delatas 是 fmdb 生成的代码内代码,也保存在同一文件夹中的 Documents 中。

标签: objective-c multithreading sqlite fmdb


【解决方案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]) {… 以确保?

【讨论】:

  • 您好,感谢您抽出宝贵时间查看此内容。我更新了我的代码,这样我就可以更容易地发现错误。此行出现错误:[db executeUpdate:@"DETACH DATABASE delta"];。数据库是可写的。我再次运行代码,它现在工作正常!我将对其进行更多测试并接受您的答案,如果没有出现,或者如果没有人对这可能是什么提出更具体的想法。谢谢!
【解决方案2】:

你已经

[db open];

在其他地方?

【讨论】:

  • 当然,我做到了。否则一开始就会失败。
【解决方案3】:

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

【讨论】:

  • 不幸的是,我无法再访问原始代码,但正如我在编辑中所写的那样,这似乎是一次问题神奇地消失了,我们没有任何进一步的问题用它。但是感谢您的回复,当我再次遇到数据库锁定错误时,我一定会回来的!
【解决方案4】:

这是一个让我感到很痛苦的地方(你知道在哪里): 我在构建一个需要附加 ATTACHed 数据库(顺便说一下,在 .NET 中)的新功能时,进行了彻底的(似乎太多了)测试。 所以我

var i = query.ExecuteNonQuery("ATTACH DATABASE @FilePath AS `MergeDestination`;", fullPath);
FakeCallThatDoesNothing()
var i = query.ExecuteNonQuery("DETACH DATABASE `MergeDestination`;");

这似乎没有足够的时间让附件发生,并导致很多人头疼。

【讨论】:

    猜你喜欢
    • 2020-01-07
    • 1970-01-01
    • 2022-01-22
    • 2020-12-02
    • 2012-02-09
    • 2018-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多