美文网首页FMDB
关于FMDB数据库崩溃和多线程研究

关于FMDB数据库崩溃和多线程研究

作者: 上帝是个女孩丶 | 来源:发表于2017-08-08 18:38 被阅读53次

    最近做项目使用本地化的时候出现一个崩溃,一开始是偶发,后来几乎高达99%的崩溃率。好吧,抽个空研究研究吧。

    rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0);

    崩溃在FMDB的这行代码上,相信很多人都遇到过。我也百度了一番,但是大多都没有解决办法。

    1. 去除多线程

    这个问题其实很简单。多线程引起的。说来也好笑,后面会讲为什么出现这个bug。

    出现崩溃而且毫无提示,好在是有触发点。研究了一番代码,发现是在数据库操作的外面套了一个异步子线程。。。

    但FMDB不能在多个线程中共同一个FMDatabase对象,因为这个类本身不是线程安全的,如果这样使用会造成数据混乱等问题。然后巧的是之前的程序员使用的加锁是数据库本身。。。那么,我使用多线程,开辟出来的线程会持有一个数据库,主线程本身也持有该数据库,这就造成了资源竞争了。然后数据库本身可能已经不唯一了。然后你用数据库作为依据去加锁,可能已经失去了本身的意义。

    所以做法很简单,去掉外部的多线程就解决问题了。

    这里提一下,数据库不是不支持多线程操作,最新版的FMDB是支持多线程操作的。多线程操作同一个数据看的时候,每个线程调用数据库的时候都及时开关,其他线程要操作数据库必须等数据库关闭后才能打开操作。当然,这样会造成混乱。不怎么推荐。

    FMDatabaseQueue:类似于线程队列。

    使用的时候可以先判断该队列是否存在,不存在再创建:(没有MarkDown排版好难受)

    FMDatabaseQueue *dbQueue = [_dbQueueDic objectForKey:dbPath];
    if (dbQueue == nil) {
        dbQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
    }

    //调用方式 多次调用亦串行

    [queue inDatabase:^(FMDatabase *db) {

        [db open];

        //可以执行多条语句,串行执行

        resultFlag = [db executeUpdate:sql];//普通执行

        resultFlag = [db executeUpdate:sql];//普通执行

        resultFlag = [db executeUpdate:sql withParameterDictionary:args];//添加参数执行

        [db close];

    }]

    3. 关于事务

    有时候我们的数据库业务,可能会考虑到数据安全唯一性,如果某段sql执行了其中一部分或者一半失效了,那么需要全部回滚,就可以用到事务操作。代码很简单,封装好的一个方法:

    [self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {

        resultFlag = [db executeUpdate:sql1];

        resultFlag = [db executeUpdate:sql2];

        resultFlag = [db executeUpdate:sql3];

      }];

    3. 为什么添加多线程

    这个还是线程问题,慢慢意识到线程真的很重要。问题:tableview上拉加载以后不展示无数据footer(阻止用户继续上拉加载),联网无问题,本地化有问题。那么很快定位到是因为网络请求是异步的,那么我们可以在子线程请求完成以后通过回调,拿到数据刷新UI。  但是本地化的时候就变成了全在主线程进行,然后就在本地化操作的最外面加了个异步的子线程。这样做到了异步回调的形式。先执行footerEndRefreshing后执行endRefreshingWithNoMore解决了该问题。

    相关文章

      网友评论

      • focusHYD:好尴尬。我也是用的你说的这个方法!但还是没有解决到!也会崩溃。我的数据量很大!几千条语句同时访问造成的崩溃。大神还有什么好的方法不
        focusHYD:@上帝是个女孩丶 没有 嵌套其他语句,只是循环几千次查询.
        上帝是个女孩丶:@释丶怀 客户端怎么会同时有几千条语句同时执行??你这样数据库内存肯定吃不消。队列原则上来说就是解决这类问题的。控制队列中线程的个数即可。4个以下最好。而且队列其实是串行的,不是循环嵌套不会出问题的,你看下你是不是在队里中执行语句的block中嵌套了其他语句
        focusHYD:@释丶怀 而且查询的时候手机CPU占用率特别高

      本文标题:关于FMDB数据库崩溃和多线程研究

      本文链接:https://www.haomeiwen.com/subject/nsqxrxtx.html