2017-06-06 92 views
1

是的,我嘗試使用fmdb在多線程操作數據庫。 我創建了一個計時器,以在子線程中以1.5s間隔查詢數據庫。 同時,它可以在主線程中用刪除,添加,編輯操作來操作數據庫。 我發現刪除添加編輯操作可能會失敗,如果查詢正在運行,說數據庫被鎖定。 我不知道在多線程如何FMDB的工作,這是我的代碼:iOS 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; 

}

回答

0

您可以使用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可能是全局使用的單例。

+0

我有一個問題:結果= [DB executeUpdateWithFormat:@ 「DELETE FROM t_messagesCache」];這樣的代碼不是立即返回結果,所以我如何保持正確的串行 –

+0

你的意思是一些任務本身是異步? –

+0

是的,我不知道這樣的代碼:bool a = [db executeUpdateWithFormat:「」]是異步或同步,它returen一個布爾類型值,所以我認爲它必須是同步,但在我的測試,它似乎異步。我很迷惑。 –

0

當數據庫打開時,我們可以執行任何操作。所以在fmdb中你不能做mutithread,因爲對於每個查詢fmdb先打開db fire查詢&返回 結果集然後再關閉它。

如果您需要執行,那麼你讓你的DB打開兩個任務..

+0

好的,但我刪除封閉的數據庫是同樣的問題。它發生的概率很小 –