移動端的數據庫,除了使用"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的以下問題: