iOS开发专题

关于FMDB报databaseislocked的解决方案

2016-08-17  本文已影响309人  老南

最近做一个二手项目,首页使用FMDB初始化了很多数据,之后应为需求需要,又加了很多初始化数据.

FMDB单例的写法是这样的:

+ (IMCache *)shareIMCache

{

static IMCache *instance = nil;

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

instance = [[IMCache alloc] init];

});

return instance;

}

- (instancetype)init

{

self = [super init];

if (self) {

NSString * dbPath = [PATH_USER_DOCUMENT stringByAppendingPathComponent:@"imcache.db"];

dbQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath];

[dbQueue inDatabase:^(FMDatabase *db) {

[db executeUpdate:[IMCache createMessageTableSql]];

[db executeUpdate:[IMCache createContectTableSql]];

}];

}

return self;

}

把数据库封装成了一个单例,添加增删改查等常用方法

使用FMDBQueue来避免访问数据库竞争冲突

FMDatabaseQueue解决这个问题的思路是:创建一个队列,然后将放入队列的block顺序执行,这样避免了多线程同时访问数据库

然而FMDB还是不可避免的就蹦了

报的就是databaseislocked

然后就开始梳理多线程的冲突,尽量避免同一时间去初始化封装成的这个单例

然而还是偶尔会崩溃

然后还是从头开始在彻查了FMDB本身

FMDatabase不能多线程使用同一个实例

前面提过了,FMdatabase是无法多线程同时访问同一个FMDatabase实例的,否则会引起崩溃.

官方给出的方案就是使用FMDatabaseQueue来解决这个问题,然而FMDatabaseQueue
能够解决的问题仅仅在于多个数据库访问请求的冲突,并不能解决多线程中多次同时初始化FMDatabase引起的崩溃

使用GCD解决多线程冲突

在知道了这问题后,想到的解决方案就是:

将不同线程多个初始化请求放入同一个队列排队依次执行

具体步骤为:

1.在单例初始化方法里初始化一个全局的串行队列

- (instancetype)init

{

self = [super init];

if (self) {

NSString * dbPath = [PATH_USER_DOCUMENT stringByAppendingPathComponent:@"imcache.db"];

dbQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath];

[dbQueue inDatabase:^(FMDatabase *db) {

[db executeUpdate:[IMCache createMessageTableSql]];

[db executeUpdate:[IMCache createContectTableSql]];

}];

serialQueue =dispatch_queue_create("FMDBThread", DISPATCH_QUEUE_SERIAL);

}

return self;

}

2.在每一个访问DataBase的方法中调用dispatch_barrier_async()方法,使用此方法创建的任务首先会查看队列中有没有别的任务要执行,如果有,则会等待已有任务执行完毕再执行;同时在此方法后添加的任务必须等待此方法中任务执行后才能执行。这样,就能够顺利解决在inDatabase后还没有关闭就再次inDatabase。

/**

*  删除所有联系人的所有聊天记录

*/

- (void)deleteAllMessages:(void(^)(BOOL success))completion

{

dispatch_barrier_async(serialQueue, ^(){

[dbQueue inDatabase:^(FMDatabase *db) {

// 查找出所有群的默认消息

NSString * sql = [NSString stringWithFormat:@"SELECT * FROM messages WHERE savetime=%@", @"0"];

NSMutableArray * messages = [NSMutableArray array];

FMResultSet * result = [db executeQuery:sql];

while ([result next]) {

CacheMessage * message = [self valueToMessage:result];

[messages addObject:message];

}

[result close];

// 删除聊天表下所有记录

NSString * deletesql = [NSString stringWithFormat:@"delete from messages"];

BOOL delete = [db executeUpdate:deletesql];

ZYNLog(@"删除聊天表 %d", delete);

// 添加群的默认消息

for (CacheMessage * msg in messages) {

NSString * insert = [NSString stringWithFormat:@"insert into messages (fromcln,tocln,uid,type,contype,status,body,sendtime,receivetime,savetime,sessionid) values ('%@','%@','%@',%d,%d,%d,\"%@\",'%@','%@',%lld,'%@')", msg.from, msg.to, msg.uid, msg.type, msg.contype, msg.status, msg.body, msg.sendtime, msg.sendtime, msg.savetime, msg.sessionid];

[db executeUpdate:insert];

}

ZYNLog(@"添加群默认消息完成");

completion(true);

}];

});

}

上一篇下一篇

猜你喜欢

热点阅读