总结:
1 数据库频繁操作打开关闭,手动打开关闭锁, 使用一个单例类操作数据库
2 避免同时操作一个资源使用队列串行方式
首先数据库是系统资源,就像我们操作文件一样,所以并发操作时要注意安全
在iOS上,只有一个线程能够打开数据库操作,其他线程要操作数据库必须等数据库关闭后才能打开操作。
多线程时:每个线程独立打开数据库,操作数据库,操作完后关闭数据库。打开和关闭都比较费时间,而且要手动控制打开关闭锁,在每个线程操作不频率时可用该方法。
如果多个线程频繁操作数据库,使用以上方法很容易造成系统崩溃,解决方案:开启第3种串行模式,使用一个类(单例方式)操作数据库。
sqlite3 多线程访问数据库
解决方案:开启串行模式
多线程操作数据库,使用FMDatabaseQueue来保证线程安全
FMDatabaseQueue解决这个问题的思路是:创建一个队列,然后将放入队列的block顺序执行,这样避免了多线程同时访问数据库;
如果是多线程各创建FMDatabaseQueue的实例,其实有多个队列,还是存在数据库竞争的问题,和用FMDatabase时是一样的;
让每个线程使用同一个Queue实例,问题就顺利解决了;
FMDB源码给出的思路
+ (instancetype)sharedInstance
{
static SyncObj* instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [SyncObj new];
});
return instance;
}
-(void) safeTest
{
io_sync_safe(^{
NSLog(@"safe print -- func safeTest()");
});
}
static const void * const NTESDispatchIOSpecificKey = &NTESDispatchIOSpecificKey;
dispatch_queue_t NTESDispatchIOQueue()
{
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue = dispatch_queue_create("db.queue", 0);
dispatch_queue_set_specific(queue, NTESDispatchIOSpecificKey, (void *)NTESDispatchIOSpecificKey, NULL);
});
return queue;
}
typedef void(^dispatch_block)(void);
void io_sync_safe(dispatch_block block)
{
if (dispatch_get_specific(NTESDispatchIOSpecificKey))
{
NSLog(@"3. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());
[NSThread sleepForTimeInterval:1];
block();
}
else
{
dispatch_sync(NTESDispatchIOQueue(), ^() {
NSLog(@"4. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());
[NSThread sleepForTimeInterval:1];
block();
});
}
}
1. 创建单利
2. 使用dispatch_queue_create创建队列
创建串行队列, 添加不同block避免同时访问