在同一数据库上使用两个FMDB队列(读 /写)



我相信我的用例很普遍,但是我找不到权威答案。

我有一种同步机制,该机制在后台运行,并将数据写入我的数据库。这个同步可能需要大量时间(我使用FTS)。为此,我使用FMDatabaseQueue。当我想在数据库上阅读时,我使用相同的队列进行查询。

现在,当同步过程已经排队到队列的很多交易时,该应用程序要进行读取时,它必须等待所有写入交易才能完成之前完成查询,因为这是一个串行队列。代码可能看起来像这样:

FMDatabaseQueue *queue = [self getDatabaseQueue];
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
    // Very slow process
    [db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
}];
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
    // Very slow process
    [db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
}];
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
    // Very slow process
    [db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
}];
[queue inDatabase:^(FMDatabase *db) {
    FMResultSet *resultSet = [db executeQuery:@"SELECT name..."];
}];

我想立即获得查询结果(即使没有完成同步),而不要等待完成UPDATE

我可以创建两个FMDatabaseQueue s,一个用于写查询,一个用于读取查询吗?如果读取查询在写入交易的中间开始会发生什么?

代码看起来像这样:

FMDatabaseQueue *writeQueue = [self getWriteDatabaseQueue];
FMDatabaseQueue *readQueue = [self getReadDatabaseQueue];
[writeQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
    // Very slow process
    [db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
}];
[writeQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
    // Very slow process
    [db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
}];
[writeQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
    // Very slow process
    [db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
}];
[readQueue inDatabase:^(FMDatabase *db) {
    FMResultSet *resultSet = [db executeQuery:@"SELECT name..."];
}];

编辑:

另外,让我感到困惑的是:

的文档

每个线程都可以做一个FMDATABASE对象。只是不要在线程上共享一个实例。

所以我从中了解到,我可以使用相同的数据库创建两个ISNTS ,但是我只需要将其保留在自己的线程上。

不,您不想让两个FMDatabaseQueue与同一数据库进行交互。FMDatabaseQueue的全部目的是通过共享单个串行队列提供单个队列来协调来自不同线程的数据库调用。

不过,我想知道您在"非常缓慢的过程"块中的代码。如果不是数据库特定的内容,则不应在inTransaction和/或inDatabase调用中。

NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init]; 
FMDatabaseQueue *databaseQueue = [FMDatabaseQueue databaseWithPath:path]; 
[backgroundQueue addOperationWithBlock:^{
    // very slow process
    [databaseQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        [db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
    }];
}];
[backgroundQueue addOperationWithBlock:^{
    // very slow process
    [databaseQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        [db executeUpdate:@"UPDATE docs SET name = ?", "value..."];
    }];
}];

当它们排队并运行时,主队列可以使用FMDatabaseQueue进行自己的databaseQueue调用,以确保其协调以使其与上面的inTransaction块同时发生:

[databaseQueue inDatabase:^(FMDatabase *db) {
    FMResultSet *resultSet = [db executeQuery:@"SELECT name..."];
    while (![resultSet next]) {
        ....
    }
}];

显然,您应该管理您的背景任务,但是适合您的应用程序(我使用了同时的操作队列,但是您可以使用串行队列或调度队列或任何您想要的任何内容)。不要陷入上述backgroundQueue的细节中,因为您的实现会有所不同。

关键观察是,您不应使用databaseQueue来管理"非常缓慢的过程"任务以及数据库交互。从inTransactioninDatabase调用中取出与数据库无关的任何内容。使用自己的队列管理您自己的非数据库相关代码。始终尽快进入databaseQueue,然后让单个共享的FMDatabaseQueue与来自多个线程的数据库协调交互。

最新更新