- (void)inDatabase:(void (^)(FMDatabase *db))block { // 通过kDispatchQueueSpecificKey来获取当前正在执行的队列,并且检查和self做比较,确保没有发生死锁,因为可以创建多个FMDatabaseQueue多个来执行不同的SQL语句 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); // 在当前queue中,同步执行block 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); }
FMResultSet *rsl = [adb executeQuery:@"select * from qfoo where foo like 'h%'"]; while ([rsl next]) { ;// whatever. }
NSLog(@"Ending query %ld", nby); }];
FMDatabasePool
If you really really really know what you’re doing and FMDatabasePool is what you really really need (ie, you’re using a read only database), OK you can use it. But just be careful not to deadlock!
// 将db放回InPool里面 - (void)pushDatabaseBackInPool:(FMDatabase*)db { if (!db) { // db can be null if we set an upper bound on the # of databases to create. return; } // 同步执行 [self executeLocked:^() { // 如果InPool数组里面包含db,说明db已经在InPool里面,不需要再放回InPool里,并且抛出异常,下面的操作就不进行了 if ([self->_databaseInPool containsObject:db]) { [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise]; } // 如果db不在InPool里面,把db加到InPool数组,并且从OutPool中移除 [self->_databaseInPool addObject:db]; [self->_databaseOutPool removeObject:db]; }]; }
- (FMDatabase*)db { __block FMDatabase *db; [self executeLocked:^() { // 从_databaseInPool里面取出最后一个FMDatabase对象 db = [self->_databaseInPool lastObject]; BOOL shouldNotifyDelegate = NO; // 如果db存在,则加到_databaseOutPool里,_databaseInPool移除掉,我的理解是_databaseOutPool是用于存放正在执行操作的db池,_databaseInPool则存放闲置的db池 // 在需要使用的时候,从闲置的池里面取出来放到正在执行的池里面 if (db) { [self->_databaseOutPool addObject:db]; [self->_databaseInPool removeLastObject]; } else { // 检查最大创建的db数量,超过了则返回,否则就根据路径,找到db if (self->_maximumNumberOfDatabasesToCreate) { NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count]; if (currentCount >= self->_maximumNumberOfDatabasesToCreate) { NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount); return; } } db = [[[self class] databaseClass] databaseWithPath:self->_path]; shouldNotifyDelegate = YES; } // 根据_openFlags和_vfsName打开db //This ensures that the db is opened before returning #if SQLITE_VERSION_NUMBER >= 3005000 BOOL success = [db openWithFlags:self->_openFlags vfs:self->_vfsName]; #else BOOL success = [db open]; #endif if (success) { // 如果代理方法响应了,但是db不允许被加到pool里面,那么db关闭释放 if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) { [db close]; db = 0x00; } else { //It should not get added in the pool twice if lastObject was found // 对于新创建的db,需要加到_databaseOutPool里,而不需要加到_databaseInPool里 if (![self->_databaseOutPool containsObject:db]) { [self->_databaseOutPool addObject:db]; // 新创建的db需要响应delegate if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) { [self->_delegate databasePool:self didAddDatabase:db]; } } } } else { NSLog(@"Could not open up the database at path %@", self->_path); db = 0x00; } }]; return db; }