iPhone中的Sqlite3数据库被锁定-如何避免?

3
我有一个查询,用于在Sqlite3 DB上执行搜索。它只是使用reader读取数据。对于每个找到的匹配项,它调用回调函数来更新结果视图。
在运行此搜索时,我在UI中点击一个按钮,该按钮将在新线程中执行其他操作。最终,它应该删除搜索控制器的视图并显示新控制器。
但是,在某些情况下,触发的操作想要写入数据库。然后它就会挂起,最终我会看到一个异常,表示数据库被锁定。
有趣的是,搜索reader也不继续执行,这是一个死锁。
我需要以特殊方式打开数据库以支持多线程使用吗?连接的构造函数应该是什么?
2个回答

1
MonoTouch 5.1+ 提供了一个 API,让您选择要与 SQLite 一起使用的线程模型。
SqliteConnection.SetConfig (SQLiteConfig.MultiThread);

这个与 SQLite 库的某些连接 选项 相映成趣。

更新:如果你使用早期版本的 MonoTouch(如 4.2 和 5.0.x 之间),你可以使用附加到错误报告 #652 的二进制文件(请按照说明操作)或者将补丁(P/Invoke 和枚举)复制粘贴到你自己的应用程序中。


抱歉,SQLiteConnection没有SetConfig方法,更准确的说,我只有SqliteConnection(请注意小写)。 我正在引用Mono.Data.Sqlite,并且我在MT 5.0.2上。 - Krumelur
抱歉,我使用源文件名,但在这种情况下,它与类型名不匹配(这是Mono源代码中使用的“正常”约定)。而且它不是5.0的一部分(它使用与4.2相同的Mono代码/分支)。我感到困惑,因为客户已经通过http://bugzilla.xamarin.com/show_bug.cgi?id=652上提供的附件进行了测试,但并非5.0.x版本。 - poupou
不,5.1(奇数版本号)是已经发布的 beta 版本,将会成为 MonoTouch 5.2(稳定版)的前身。 - poupou
我没有注意到这个添加。它可能来自于继承自Mono基类库的源代码(我们获得了共享的错误修复和增强功能),或者(不太可能)是我编译程序集时出现了问题。从记忆中看,ExecuteReader可以返回多行(与ExecuteQuery的一行相比),因此在某些情况下可能需要更多的资源。 - poupou
我复制了这些行和外部调用,但是我得到了错误代码21,即“库使用不正确”。看来我必须等待MT 5.2版本。 - Krumelur
显示剩余2条评论

1

我不确定我是否正确理解了您的描述,但是根据您的描述,我认为您的“读取器”逐行遍历数据库,并且每次找到结果时都会回调到一个回调函数?这是正确的吗?

如果是这样,您可能会反复锁定您的数据库,而且搜索速度会很慢。

正确的方法是在一次查询中提取所有匹配项的结果集 - 一旦完成该查询,锁定将被释放,并且您将从SQL中获得仅包含匹配行的结果集。

您可以通过使用类型为“SELECT * FROM tablename WHERE columnX LIKE '%searchstring%'”(或类似的,具体取决于您的搜索条件)的查询让SQLite创建这样的结果集。

这将创建一个包含数据库中所有匹配项的结果集,然后释放数据库锁。然后,您可以遍历结果并创建对象,并将其放入连接到您的UI视图的NSArray中。

NSArray retval = [NSMutableArray array];

//Create a query
NSString *query = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@ LIKE %@", 
tableName, columnName, searchString];

sqlite3_stmt *statement;

//Database locks here
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil) 
== SQLITE_OK) {
    //Database should unlock here, the query is finished
    while (sqlite3_step(statement) == SQLITE_ROW) {
        char *nameChars = (char *) sqlite3_column_text(statement, 0);
        NSString *name = [NSString stringWithUTF8String:nameChars];
        SomeClass *info = [[SomeClass alloc] initWithName:name];

        /* Extract other columns and put in your object */

        [retval addObject:info];
        [info release];
    }
sqlite3_finalize(statement);
} else {
    NSLog(@"SQL-statement failed");
}

这样做的话,在必要时写入数据库就不应该有问题。只有在绝对必要的情况下才向数据库执行新查询,例如当您的搜索条件发生变化或数据库中的内容已更新时。

不要对未更改的数据库或具有未更改的搜索条件运行重复查询。


问题是:查询非常非常慢。所以我不想等到查询完成。我想在找到结果时立即显示结果。但是感谢您解释锁定问题! - Krumelur
哦,而在Monotouch中似乎我唯一的选项是对命令执行ExecuteReader()。虽然有Prepare()方法但没有Step或类似的东西。 - Krumelur
我只使用iOS SDK中包含的sqlite3-lib库,没有其他需要,它们已经足够了。 - jake_hetfield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接