移动端的数据库,除了使用"SQLite"这个共识,基本各自为政。git
iOS这边以前使用的是基于SQLite封装的FMDB。一开始使用并没有问题。但在长期的使用中反映出,有性能瓶颈,好比说某个用户长期未登陆,在登陆时收到大量消息,因为FMDB不支持多线程的写操做,会致使写入很慢。github
遇到性能瓶颈后咱们开始寻找FMDB的替代品,就是WCDB,微信开源官方移动端数据库组件。进入咱们的实现。依托微信的用户量和对数据库的依赖,WCDB已经处理了不少坑点和瓶颈,开源1年多,不断地迭代功能,完善文档。同时WCDB在Github的wiki上提供了专门的教程,帮助使用FMDB的开发者进行迁移。sql
对于已经上线运行的项目,解决性能瓶颈会是一个常见的迁移理由。相较于FMDB直白的封装,WCDB上到OC层的ORM,下到SQLite源码,都作了各种性能优化。 为了验证优化效果,微信提供benchmark,并将性能测试结果和测试代码上传到了Github。同时,benchmark中也加入了FMDB的测试代码,用于横向比较。 如下性能测试均为WAL模式、缓存大小2000字节、页大小4 kb:数据库
PRAGMA cache_size=-2000
PRAGMA page_size=4096
PRAGMA journal_mode=WAL
复制代码
测试数据均为含有一个整型和一个二进制数据的表:CREATE TABLE benchmark(key INTEGER, value BLOB),二进制数据长度为100字节。缓存
因为FMDB和WCDB都基于SQLite,所以二者在数据库的文件格式上一致。用FMDB建立、操做的数据库,能够直接经过WCDB打开、使用。所以开发者无需作额外的数据迁移。性能优化
WCDB提供了ORM的功能,将类的属性绑定到数据库表的字段。在平常实践中,类的属性名和表的字段名一般不一致。所以,WCDB提供了WCDB_SYNTHESIZE_COLUMN(className, propertyName, columnName)宏,用于映射属性名。 对于 表:CREATE TABLE message (db_id INTEGER, db_content TEXT) 类:bash
//Message.h
@interface Message : NSObject
@property int localID;
@property(retain) NSString *content;
@end
//Message.mm
@implementation Message
@end
复制代码
这里表字段都加了"db_"的前缀,而且使用了不同的字段名。经过WCDB的ORM,能够映射为微信
//Message.h
@interface Message : NSObject <WCTTableCoding>
@property int localID;
@property(retain) NSString *content;
WCDB_PROPERTY(localID)
WCDB_PROPERTY(content)
@end
//Message.mm
@implementation Message
WCDB_IMPLEMENTATION(Message)
WCDB_SYNTHESIZE_COLUMN(Message, localID, "db_id")
WCDB_SYNTHESIZE_COLUMN(Message, content, "db_content")
@end
复制代码
经过WCDB_SYNTHESIZE_COLUMN宏映射后,WCDB一样能兼容FMDB的表结构,开发者也不须要作数据迁移。因为WCDB较之FMDB性能上有着较大提高,迁移起来因为都是基于SQLite封装,基本上都是兼容的,因此咱们决定使用WCDB。多线程
替换前代码并发
+ (BOOL)insertGroupInfoData:(KitGroupInfoData *)infoData{
BOOL result;
//UPDATE
KitGroupInfoData *groupInfoExit = [KitGroupInfoData getGroupInfoWithGroupId:infoData.groupId];
if(groupInfoExit){//存在 updateHIYUNTON Group
NSString *sql = [NSString stringWithFormat:@"UPDATE %@ SET groupName = ?, declared = ?, memberCount = ?,type = ?,isAnonymity = ?,isDiscuss = ? WHERE groupId = '%@' ",DATA_GROUPINFO_DBTABLE,infoData.groupId];
result = [self updateTable:sql,!KCNSSTRING_ISEMPTY(infoData.groupName)? infoData.groupName:@"",!KCNSSTRING_ISEMPTY(infoData.declared)?infoData.declared:@"",[NSNumber numberWithInteger:infoData.memberCount],[NSNumber numberWithInteger:infoData.type],infoData.isAnonymity?@"1":@"0",infoData.isDiscuss?@"1":@"0"];
return result;
}else{//不存在insert
NSString *sql = [NSString stringWithFormat:@"INSERT INTO %@ %@", DATA_GROUPINFO_DBTABLE, @"(groupId, groupName ,declared, createTime,owner,memberCount,type,isAnonymity,isDiscuss) VALUES (?, ?, ? , ?, ?, ?, ?,?,?)"];
result = [self updateTable:sql,infoData.groupId, infoData.groupName,infoData.declared,infoData.createTime,infoData.owner,[NSNumber numberWithInteger:infoData.memberCount],[NSNumber numberWithInteger:infoData.type],infoData.isAnonymity?@"1":@"0",infoData.isDiscuss?@"1":@"0"];
return result;
}
return YES;
}
+ (BOOL)upDateGroupInfo:(KitGroupInfoData *)groupInfo{
__block BOOL result;//UPDATE
[[[KitDataBaseManager sharedInstance] userDB_Queue] inDatabase:^(FMDatabase *db) {
[db open];
NSString *sql = [NSString stringWithFormat:@"UPDATE %@ SET groupName = ?, declared = ?,owner = ? WHERE groupId = '%@' ",DATA_GROUPINFO_DBTABLE,groupInfo.groupId];
result = [db executeUpdate:sql,!KCNSSTRING_ISEMPTY(groupInfo.groupName)? groupInfo.groupName:@"",!KCNSSTRING_ISEMPTY(groupInfo.declared)?groupInfo.declared:@"",groupInfo.owner];
[db close];
}];
return result;
}
复制代码
替换后代码
+ (BOOL)insertGroupInfoData:(KitGroupInfoData*)infoData{
WCTDatabase *dataBase = [DataBaseManager sharedInstance].dataBase;
return [dataBase insertOrReplaceObject:infoData into:DATA_GROUPINFO_DBTABLE];
}
+ (BOOL)upDateGroupInfo:(KitGroupInfoData *)groupInfo{
WCTDatabase *dataBase = [DataBaseManager sharedInstance].dataBase;
return [dataBase updateRowsInTable:DATA_GROUPINFO_DBTABLE onProperties:{KitGroupInfoData.groupName,KitGroupInfoData.declared,KitGroupInfoData.owner} withObject:groupInfo where:KitGroupInfoData.groupId == groupInfo.groupId];
}
复制代码
在使用了WCDB以后,代码变得更加简洁的同时,性能还获得了提升,也不须要额外关注数据库升级和多线程操做的问题。WCDB还提供了加密、统计、修复等功能供咱们使用。在解决性能瓶颈的同时,也解决以前使用FMDB的以下问题: