FMDB与线程安全

作者: 踏云小子 | 来源:发表于2017-06-01 17:36 被阅读198次

    简介

    FMDB是对苹果SQLite的封装

    多线程操作

    1. 如果出现多个线程同时操作数据库,怎么办,用他,用他,FMDatabaseQueue
    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
    
    [queue inDatabase:^(FMDatabase *db) {
            
            [db executeUpdate:@"INSERT INTO myTable (name) VALUES (?)", @"will"];
            [db executeUpdate:@"INSERT INTO myTable (name) VALUES (?)", @"carter"];
            
            FMResultSet *rs = [db executeQuery:@"select name from myTable"];
            while([rs next]) {
                NSString *obj = [rs stringForColumn:@"name"];
                NSLog(@"%@", obj);
            }
            
        }];
    
    2. 大量查询数据库的情况

    比如循环1000次执行插入查询的操作

    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.filePath];
        for (NSInteger i = 0; i < 1000; i ++) {
            [queue inDatabase:^(FMDatabase *db) {
                
                [db executeUpdate:@"INSERT INTO myTable (name) VALUES (?)", @"will"];
                [db executeUpdate:@"INSERT INTO myTable (name) VALUES (?)", @"carter"];
                
                FMResultSet *rs = [db executeQuery:@"select name from myTable"];
                while([rs next]) {
                    NSString *obj = [rs stringForColumn:@"name"];
                    NSLog(@"%@", obj);
                }
                
            }];
        }
    
    image.png

    结果发现按钮一直处于被点击状态,说明已经阻塞了主线程,看了inDatabase的源码

    FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey);
        assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock");
        
        FMDBRetain(self);
        
        dispatch_sync(_queue, ^() {
            
            FMDatabase *db = [self database];
            block(db);
            
            if ([db hasOpenResultSets]) {
                NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]");
                
    #if defined(DEBUG) && DEBUG
                NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]);
                for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) {
                    FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue];
                    NSLog(@"query: '%@'", [rs query]);
                }
    #endif
            }
        });
        
        FMDBRelease(self);
    

    发现他是用同步的方法进行的操作,这样就避免了多线程锁死的情况,但是确定呢就是会阻塞主线程,所以,有如下解决方法:

    • 在inDatabase的外面套了个异步,就不会阻塞主线程了
    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.filePath];
        for (NSInteger i = 0; i < 1000; i ++) {
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                [queue inDatabase:^(FMDatabase *db) {
                    
                    [db executeUpdate:@"INSERT INTO myTable (name) VALUES (?)", @"will"];
                    [db executeUpdate:@"INSERT INTO myTable (name) VALUES (?)", @"carter"];
                    
                    FMResultSet *rs = [db executeQuery:@"select name from myTable"];
                    while([rs next]) {
                        NSString *obj = [rs stringForColumn:@"name"];
                        NSLog(@"%@", obj);
                    }
                    
                }];
            });
        }
    
    image.png image.png

    哈哈,就是线程有点多

    • 用inTransaction事务方法查询,会比inDatabase速度快些
    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.filePath];
        [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
            for (NSInteger i = 0; i < 1000; i ++) {
                BOOL isSuccess = [db executeUpdate:@"INSERT INTO myTable (name) VALUES (?)", @"will"];
                
                if (!isSuccess) {
                    *rollback = YES;
                    break;
                }else{
                    NSLog(@"success");
                }
                
            }
        }];
    
    • 或者拆解查询的数量,慢慢来
    3. 前面的FMDatabaseQueue都是用同步的方法来实现,我们自定义一个FMDatabaseAsynQueue,用异步加线程锁的方法尝试看看

    相关文章

      网友评论

        本文标题:FMDB与线程安全

        本文链接:https://www.haomeiwen.com/subject/krdefxtx.html