iOS开发-FMDB多线程安全问题

为什么使用FMDB会有线程安全问题

现在,大家为了性能上面的提升,都会使用多线程来处理一些数据,所以,多个线程同时访问同一个数据库是不可避免的。如果不做线程安全处理,可能会导致得到的数据的不正确的,严重的情况下甚至会导致程序崩溃。

举个简单的例子

假设当前线程1正在访问数据库A,这时,线程2也正好要反问数据库A,如果没有做线程安全处理,线程2就有可能把线程1的访问数据库进程结束掉,显然,无论结果如何,这都是非常危险的。

怎么做线程安全

使用FMDatabaseQueue

现在数据库第三方库普遍都是使用FMDB的,这里,我也简单说明一下FMDB的多线程管理吧。在FMDB的文档中,也有说到多线程处理的问题。FMDB的多线程处理是比较简单的,只需要我们使用FMDatabaseQueue类创建实例对象,这个对象里面已经帮我们封装好了FMDatabase对象,这也就意味着我们不需要关心FMDatabase的创建了。

加入GCD信号量控制

在GCD中有三个函数是semaphore的操作,分别是:
  dispatch_semaphore_create   创建一个semaphore
  dispatch_semaphore_signal   发送一个信号
  dispatch_semaphore_wait    等待信号
  
  简单的介绍一下这三个函数,第一个函数有一个整形的参数,我们可以理解为信号的总量,dispatch_semaphore_signal是发送一个信号,自然会让信号总量加1,dispatch_semaphore_wait等待信号,当信号总量少于0的时候就会一直等待,否则就可以正常的执行,并让信号总量-1,根据这样的原理,我们便可以快速的创建一个并发控制来同步任务和有限资源访问控制。
  
  利用这个原理,我们可以在访问数据库的时候加入这个信号量控制。
  

实现步奏

  • 创建FMDatabaseQueue对象
g_fmDatabaseQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
  • 使用FMDatabaseQueue的对象访问数据库

    [g_fmDatabaseQueue inDatabase:^(FMDatabase *db) {
        BOOL success = [db executeUpdate:sql];
    }];
  • 加入信号量控制

    //创建一个信号量,初始值为0
    __block dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    

[g_fmDatabaseQueue inDatabase:FMDatabase *db {
BOOL success = [db executeUpdate:sql];

    //给信号量+1
    dispatch_semaphore_signal(sem);
}];

//等待信号量为1
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);

 - 关闭数据库

```objctive-c
[g_fmDatabaseQueue close];

主要事项

  1. 这里面都是使用block来访问数据库的,要注意防止内存泄露和内存提前释放。