簡介
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");
}
}
}];
- 或者拆解查詢的數量,慢慢來