操作数据库时,如果是有多个并发线程同时使用到了同一个数据库,就有可能发生同时操作的可能,这个时候数据会崩溃。FMDB 给我们提供了FMDatabaseQueue 这样一种解决方法。
自己用GCD 的demo 测试后,可以初步确定,FMDatabaseQueue 能做到线程安全是 因为他使用了串行队列,即在FMDatabaseQueue.m 文件里面的这行代码:
_queue = dispatch_queue_create([[NSStringstringWithFormat:@"fmdb.%@",self]UTF8String],NULL);
关于dispatch_queue_create 的第二个参数其实是有两种的,即为:
串形队列 DISPATCH_QUEUE_SERIAL
并行队列 DISPATCH_QUEUE_CONCURRENT
而 DISPATCH_QUEUE_SERIAL其实是 NULL 的宏,所以说FMDatabaseQueue创建了一个串行队列,这个串行队列有什么特性而使得数据库操作可以安全进行而不会并发执行呢?
下面我会用GCD的代码进行测试,这里我先说一下结论:假设有三个GCD并发线程,在这三个线程里面执行串行线程。那么,虽然这三个线程会像并发线程一样无序执行(无序是因为这三个串行线程是在三个并发线程里面生成的,自然是并发线程无序执行后再生成此串行线程),但是却并不会并发执行,而按顺序一个串行线程执行完毕才到下一个串行线程,因此保证了数据库不会被并发执行而崩溃。
以下为测试代码:
- (void)doSomething:(NSString *)str
{
[NSThreadsleepForTimeInterval:1.0];
NSLog(@"====%@====",str);
}
- (void)viewDidLoad
{
_globalQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
_seriQueue =dispatch_queue_create("myQueueSerial",DISPATCH_QUEUE_SERIAL);
[self methodTwo];
}
- (void)methodTwo
{
dispatch_async(_globalQueue, ^{
NSLog(@"11%@",[NSThreadcurrentThread]);
dispatch_sync(_seriQueue, ^{
[selfdoSomething:@"A"];
NSLog(@"12%@",[NSThreadcurrentThread]);
});
// [self doSomething:@"A"];
});
dispatch_async(_globalQueue, ^{
NSLog(@"21%@",[NSThreadcurrentThread]);
dispatch_sync(_seriQueue, ^{
NSLog(@"22%@",[NSThreadcurrentThread]);
[selfdoSomething:@"B"];
});
// [self doSomething:@"B"];
});
dispatch_async(_globalQueue, ^{
NSLog(@"31%@",[NSThreadcurrentThread]);
dispatch_sync(_seriQueue, ^{
NSLog(@"32%@",[NSThreadcurrentThread]);
[selfdoSomething:@"C"];
});
// [self doSomething:@"C"];
});
}
运行的结果如下:
15:16:19.763 GCDDemo[21028:897286] 11<NSThread: 0x7fa4a0774ee0>{number = 2, name = (null)}
15:16:19.763 GCDDemo[21028:897288] 31<NSThread: 0x7fa4a070a330>{number = 4, name = (null)}
15:16:19.762 GCDDemo[21028:897287] 21<NSThread: 0x7fa4a052b700>{number = 3, name = (null)}
15:16:20.765 GCDDemo[21028:897286] ====A====
15:16:20.765 GCDDemo[21028:897286] 12<NSThread: 0x7fa4a0774ee0>{number = 2, name = (null)}
15:16:20.766 GCDDemo[21028:897288] 32<NSThread: 0x7fa4a070a330>{number = 4, name = (null)}
15:16:21.767 GCDDemo[21028:897288] ====C====
15:16:21.767 GCDDemo[21028:897287] 22<NSThread: 0x7fa4a052b700>{number = 3, name = (null)}
15:16:22.769 GCDDemo[21028:897287] ====B====
可以看出, A B C 虽然无序执行,而且也不在同一个线程上,但是他们却是串行执行的,即只有当一个任务执行完毕后(也就是一秒之后)才会执行下一个任务,所以在同一个串行队列里面去操作数据是安全的。