美文网首页
FMDB 源码阅读

FMDB 源码阅读

作者: 取个名字真困难 | 来源:发表于2018-11-09 22:37 被阅读0次

    面试的时候被问到了 说FMDB如何是实现数据的安全的,我当时没有去看源码,直接猜测是加了锁,后来发现不是,现在补上功课。跟我有一样想法的小伙伴一起分享。

    1.主要涉及的类

    FMDdatabase,FMResultSet,FMDatabaseQueue,FMDatabaseAddition,FMDatabasePool
    

    2.源码分析:

       FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
    

    点进去发现调用的是

    + (instancetype)databaseQueueWithPath:(NSString*)aPath {
    
        FMDatabaseQueue*q = [[self alloc]initWithPath:aPath];
    
        FMDBAutorelease(q);
    
        return q;
    
    }
    

    继续点进去看[[self alloc]initWithPath:aPath];

    - (instancetype)initWithPath:(NSString*)aPath {
    
        // default flags for sqlite3_open
    
        return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE vfs:nil];
    
    }
    

    继续走看 [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE vfs:nil];

    - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString*)vfsName {
    
        self= [superinit];
    
        if(self!=nil) {
    
            _db = [[[self class] databaseClass] databaseWithPath:aPath];
    
            FMDBRetain(_db);
    
    #if SQLITE_VERSION_NUMBER >=3005000
    
            BOOL success = [_dbopenWithFlags:openFlagsvfs:vfsName];
    #else
            BOOLsuccess = [_db open];
    #endif
    
            if(!success) {
    
                NSLog(@"Could not create database queue for path %@", aPath);
                FMDBRelease(self);
                return0x00;
            }
    
            _path=FMDBReturnRetained(aPath);
    
            _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL);   //这里创建了一个自定义串行队列
    
            dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL); //添加标记 根据标记取出来,确保是同一个队列
    
            _openFlags= openFlags;
            _vfsName= [vfsNamecopy];
        }
        return self;
    
    }
    

    具体更新数据的API

     [queue inDatabase:^(FMDatabase *db) {
    
            [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
    
            [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
    
            [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];
    
            FMResultSet *rs = [db executeQuery:@"select * from foo"];
    
            while ([rs next]) {
    
                //…
    
            }
    
        }];
    

    点进去inDatabase 会来到下面的这个方法

    - (void)inDatabase:(__attribute__((noescape))void(^)(FMDatabase*db))block {
    
    #ifndef NDEBUG
    
        /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue
    
         * and then check it against self to make sure we're not about to deadlock. */
    
        FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey);//根据kDispatchQueueSpecificKey取出来FMDatabaseQueue(当初存进去的是self)
    
        assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock");
    
    通过判断currentSyncQueue和 self 达到判断 FMDatabaseQueue 中的queue的目的。每一个FMDatabaseQueue对象都有一个dispatch_Queue_t. 大神的代码果然有思想。
    
    断言确保当前要执行的队列和正在执行的队列不是同一个队列,否则会引起死锁。
    
    #endif
    
        FMDBRetain(self);
    
    下面是在串行队列发起一个同步任务。
        dispatch_sync(_queue, ^() {
    
            FMDatabase*db = [self database];
    
            block(db);
    
            if([dbhasOpenResultSets]) {
    
                NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]");
    
    #if defined(DEBUG) && DEBUG
    
                NSSet*openSetCopy =FMDBReturnAutoreleased([[dbvalueForKey:@"_openResultSets"]copy]);
    
                for(NSValue*rsInWrappedInATastyValueMeal in openSetCopy) {
    
                    FMResultSet*rs = (FMResultSet*)[rsInWrappedInATastyValueMealpo interValue];
    
                    NSLog(@"query: '%@'", [rs query]);
    
                }
    
    #endif
    
            }
    
        });
    
        FMDBRelease(self);
    
    }
    

    3.总结

    FMDB 主要使用串行队列执行同步任务的方式来保证数据的安全的。

    相关文章

      网友评论

          本文标题:FMDB 源码阅读

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