【问题标题】:iOS FMDB multithreading operation failureiOS FMDB 多线程操作失败
【发布时间】:2017-06-06 01:53:09
【问题描述】:

是的,我尝试使用 fmdb 在多线程中操作数据库。 我创建了一个计时器来在子线程中以 1.5 秒的间隔查询数据库。 同时,它可以在主线程中对数据库进行删除、添加、编辑操作。 我发现如果查询正在运行,删除添加编辑操作可能会失败。它说数据库被锁定。 我不知道 fmdb 如何在多线程中工作,这是我的代码:

-(NSArray *)list{

NSString *path = [[PathHelper cachePath] stringByAppendingString:@"/MessagesCache.db"];
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
NSMutableArray *list = [NSMutableArray array];
[queue inDatabase:^(FMDatabase *db) {
    [db open];
    FMResultSet *set = [db executeQuery:@"SELECT * FROM t_messagesCache ORDER BY triggerTime ASC;"];

    while (set.next) {

        MXNIMMessageModel *message = [MXNIMMessageModel new];
        message.msgType = [set intForColumn:@"msgType"];
        message.uid = [set stringForColumn:@"uid"];
        message.msg = [set stringForColumn:@"msg"];
        message.nickname = [set stringForColumn:@"nickname"]; ;
        message.name = [set stringForColumn:@"name"];
        message.url = [set stringForColumn:@"url"];
        message.ext = [set stringForColumn:@"ext"];
        message.dur = [set intForColumn:@"dur"];
        message.w = [set intForColumn:@"w"];
        message.h = [set intForColumn:@"h"];
        message.size = [set intForColumn:@"size"];
        message.lastInterval = [set intForColumn:@"lastInterval"];
        message.md5 = [set stringForColumn:@"md5"];
        message.sort = [set intForColumn:@"sort"];
        message.triggerTime = [set stringForColumn:@"triggerTime"];
        message.teamId = [set stringForColumn:@"teamId"];

        [list addObject:message];

    }
    [db close];

}];
return list;

}

- (BOOL)deleteMessageModelByUid:(NSString *)uid

{

__block BOOL result;
NSString *path = [[PathHelper cachePath] stringByAppendingString:@"/MessagesCache.db"];
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
[queue inDatabase:^(FMDatabase *db) {
    [db open];
    result = [db executeUpdateWithFormat:@"DELETE FROM t_messagesCache WHERE uid = %@",uid];
    [db close];
}];

return result;

}

【问题讨论】:

    标签: ios xcode fmdb


    【解决方案1】:

    我们可以在数据库打开时执行任何操作。所以在 fmdb 中你不能做多线程,因为对于每个查询 fmdb 首先打开 db fire 查询 &return 结果集,然后再次关闭它。

    如果你需要执行,那么你让你的数据库为这两个任务打开..

    【讨论】:

    • 好的,但我删除关闭的数据库是同样的问题。它发生的概率很小
    【解决方案2】:

    您可以使用 GCD SERIAL QUEUE 将所有 FBMD 操作保留在一个线程上。

    首先,定义一个全局串行队列:

    @interface ExampleClass 
    @property(nonatomic,strong) dispatch_queue_t queue;
    @end
    
    @implementation ExampleClass
    //......
    - (dispatch_queue_t)queue {
        if (_queue != nil) {
            _queue = dispatch_queue_create("SERIAL_QUEUE", DISPATCH_QUEUE_SERIAL);
        }
        return _queue;
    }
    //......
    @end
    

    那么,队列中的操作FMDB,将所有操作保持在一个线程上:

    //For list
    dispatch_async(self.queue, ^{
        //NSArray *list = [yourObjectForFMDB list];
        dispatch_async(dispatch_get_main_queue(), ^{
            //do UI operation with list
        });
    });
    
    //For deleting
    dispatch_async(self.queue, ^{
        //[yourObjectForFMDB deleteMessageModelByUid:@"1"];
    });
    

    理论:dispatch_async 会创建一个新线程来执行任务,而一个SERIAL QUEUE 确保只创建一个线程。

    这里的 ExampleClass 可以是一个供全局使用的单例。

    【讨论】:

    • 我有一个问题:result = [db executeUpdateWithFormat:@"DELETE FROM t_messagesCache"];像这样的代码不是立即返回结果,所以我怎样才能保持正确的串行
    • 你的意思是有些任务本身是异步的吗?
    • 是的,我不知道这样的代码: bool a = [db executeUpdateWithFormat:""] 是异步或同步,它返回一个布尔类型值,所以我认为它必须是同步的,但在我的测试,它似乎是异步的。我很困惑。
    • 通常,如果一个方法返回一个值,它就是同步的。如果方法提供了一个回调块,它是异步的。对于异步情况,您还可以对方法调用者使用块回调。
    • 好的,那么我如何在多线程中使用 fmdb,我使用 'inDatabase' 方法,但有时插入或删除方法不起作用,甚至有时会导致访问错误。你有吗在案例中练习。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    相关资源
    最近更新 更多