WCDB的基本使用

前言

WCDB是微信移動端團隊開源的移動端數(shù)據(jù)庫組件邓深,提供了一個高效杜窄、完整侄旬、易用的移動端存儲方案望抽。第一次應用到WCDB還是在現(xiàn)公司的工程中加矛,由于現(xiàn)在的team成員主要來自鵝廠,在工程中應用到前東家的東西也是理所當然煤篙,這同時也充分說明了WCDB的易用性斟览,不好用誰會繼續(xù)再使用它呢?本文主要是對WCDB做簡單的介紹以及使用方法的歸納總結(jié)辑奈。

為什么選擇WCDB

  • 之所以選擇WCDB苛茂,主要還是因為它的高效已烤、完整、易用性妓羊。
  1. 高效
    WCDB支持多線程的讀讀胯究、讀寫并發(fā)以及寫寫串行執(zhí)行,在批量寫操作的性能測試中躁绸,WCDB性能是FMDB的180%左右裕循。


    批量讀寫操作性能對比.jpg

    而在多線程讀寫操作中,WCDB的多線程讀寫操作性能優(yōu)于FMDB 62% 涨颜,而多線程讀操作基本與FMDB持平费韭。FMDB在多線程寫測試中茧球,直接返回錯誤SQLITE_BUSY庭瑰,因此無法比較。而基于SQLite的機制抢埋,WCDB的多線程寫操作實質(zhì)也是串行執(zhí)行弹灭,但不會出錯導致操作中斷。


    多線程讀寫操作性能對比.jpg
  2. 完整
    加密:WCDB提供基于SQLCipher的數(shù)據(jù)庫加密揪垄。
    損壞修復:WCDB內(nèi)建了Repair Kit用于修復損壞的數(shù)據(jù)庫穷吮。
    WCDB提供接口直接獲取SQL的執(zhí)行耗時,可用于監(jiān)控性能饥努。
    反注入:WCDB內(nèi)建了對SQL注入的保護
  3. 易用
    WCDB的查詢語言是用WINQ進行查詢捡鱼,無需為了拼接SQL字符串寫很長的代碼。
    WCDB的對象關系映射也非常方便酷愧,可以很便捷地定義表驾诈、索引、約束和增刪改查操作等溶浴。

WCDB的使用

  • 創(chuàng)建數(shù)據(jù)庫
-(WCTDatabase *)db {
    if (_db) {
        return _db;
    }
    //獲取沙盒根目錄
    NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    // 文件路徑
    NSString *filePath = [documentsPath stringByAppendingPathComponent:@"RSDBService.sqlite"];
    NSLog(@"path = %@",filePath);
    _db = [[WCTDatabase alloc]initWithPath:filePath];
    if (![_db canOpen]) {
        NSLog(@"RSDBService.sqlite canOpen fail");
        [_db createTableAndIndexesOfName:@"" withClass:[NSArray class]];
    }
    return _db;
}
  • 對象關系映射

WCDB使用內(nèi)建的宏實現(xiàn)ORM的功能乍迄,通過ORM可以達到直接通過Object進行數(shù)據(jù)庫操作。此處需要注意的一點是士败,由于WCDB是基于Objective C++闯两,如果在model的頭文件中引入了<WCDB/WCDB.h>,就需要把.m文件改變?yōu)?mm文件谅将。為了不影響到使用model的controller或者view類漾狼,此處可以用category特性將wcdb的引用隔離。在category中引用<WCDB/WCDB.h>饥臂,并遵守WCTTableCoding協(xié)議邦投,使用WCDB_PROPERTY將聲明綁定到數(shù)據(jù)庫表的字段。以下用一個好友關系的contactModel做舉例說明

首先是category文件擅笔,category中需要引入<WCDB/WCDB.h>并遵守WCTTableCoding協(xié)議

#import "RSContactModel.h"
#import <WCDB/WCDB.h>

@interface RSContactModel (WCTTableCoding) <WCTTableCoding>

WCDB_PROPERTY(uid)
WCDB_PROPERTY(nickName)
WCDB_PROPERTY(avatarUrl)
WCDB_PROPERTY(sex)
WCDB_PROPERTY(delFlag)
WCDB_PROPERTY(addFriendImgUrl)
WCDB_PROPERTY(registerTime)
WCDB_PROPERTY(addFriendTime)

@end

然后是.h文件志衣,在.h中主要做的就是將model所需要暴露的屬性暴露出來屯援,以供其他類使用

#import <UIKit/UIKit.h>
#import "RSModel.h"
#import "Spcgicommdef.pbobjc.h"

@interface RSContactModel : RSModel
@property (nonatomic, strong) NSString *nickName;
@property (nonatomic, assign) long long uid;
@property (nonatomic, strong) NSString *avatarUrl;
@property (nonatomic, assign) RSenSex sex;
@property (nonatomic, assign) RSenDelFlag delFlag;
@property (nonatomic, strong) NSString *addFriendImgUrl;
@property (nonatomic, assign) int32_t registerTime;
@property (nonatomic, assign) int32_t addFriendTime;
@end

最后是.m文件,在.m文件中需要定義類文件中綁定到數(shù)據(jù)庫表的字段以及主鍵的設置念脯、索引的設置以及約束等狞洋。并且在init方法中通過dispacth_once初始化數(shù)據(jù)庫表。

#import "RSContactModel+WCTTableCoding.h"
#import "RSContactModel.h"
#import <WCDB/WCDB.h>
#import "RSDBService.h"

@implementation RSContactModel

WCDB_IMPLEMENTATION(RSContactModel)
WCDB_SYNTHESIZE(RSContactModel, nickName)
WCDB_SYNTHESIZE(RSContactModel, uid)
WCDB_SYNTHESIZE(RSContactModel, avatarUrl)
WCDB_SYNTHESIZE(RSContactModel, sex)
WCDB_SYNTHESIZE(RSContactModel, addFriendImgUrl)
WCDB_SYNTHESIZE_DEFAULT(RSContactModel, delFlag, 0);
WCDB_SYNTHESIZE(RSContactModel, registerTime)
WCDB_SYNTHESIZE(RSContactModel, addFriendTime)
WCDB_UNIQUE(RSContactModel, uid)
WCDB_NOT_NULL(RSContactModel, uid)
-(instancetype)init {
    self = [super init];
    if (self) {
        static dispatch_once_t token;
        dispatch_once(&token, ^{
            [RSContactModel createDBTable];
        });
    }
    return self;
}

+(void)createDBTable {
    if ([[RSDBService db] createTableAndIndexesOfName:NSStringFromClass([RSContactModel class]) withClass:[RSContactModel class]]) {
        NSLog(@"creat table RSContactModel success");
    } else {
        NSLog(@"creat table RSContactModel fail");
    }
}
@end

WCDB_PROPERTY用于在頭文件中聲明綁定到數(shù)據(jù)庫表的字段绿店。

WCDB_IMPLEMENTATION吉懊,用于在類文件中定義綁定到數(shù)據(jù)庫表的類。同時假勿,該宏內(nèi)實現(xiàn)了WCTTableCoding借嗽。因此,開發(fā)者無須添加更多的代碼來完成WCTTableCoding的接口

WCDB_SYNTHESIZE转培,用于在類文件中定義綁定到數(shù)據(jù)庫表的字段恶导。

WCDB_PRIMARY用于定義主鍵

WCDB_PRIMARY_AUTO_INCREMENT 用于定義自增主鍵

WCDB_INDEX用于定義索引

WCDB_UNIQUE用于定義唯一約束

WCDB_NOT_NULL用于定義非空約束

  • 增刪改查CRUD

對數(shù)據(jù)庫訪問的接口實現(xiàn)建議提供專門的Service類來進行操作,比如對好友關系的數(shù)據(jù)庫模型可以提供一個專門的RSContactService來對RSContact表進行操作浸须。如果熟悉RAC的話惨寿,可以在Service中結(jié)合RAC的信號來通知業(yè)務層說該數(shù)據(jù)庫表有更新。

1.增:

-(BOOL)saveContactList:(NSArray *)contactList {
    //contactList中為服務端下發(fā)的contact列表
    NSMutableArray *tmp = [[NSMutableArray alloc] init];
    for (RSContact *contact in contactList) {
        RSContactModel *model = [[RSContactModel alloc] init];
        model.uid = contact.uin;
        model.nickName = contact.nickName;
        model.avatarUrl = contact.headImgURL;
        model.sex = (RSenSex)contact.sex;
        model.delFlag = (RSenDelFlag)contact.delFlag;
        model.addFriendImgUrl = contact.addFriendImgURL;
        model.registerTime = contact.registerTime;
        model.addFriendTime = contact.addFriendTime;
        [tmp addObject:model];
    }
    BOOL result = [[RSDBService db] insertOrReplaceObjects:tmp into:NSStringFromClass([RSContactModel class])];
    if (result) {
        [self.updateSignal sendNext:@(YES)];
        //如果result為true表示插入數(shù)據(jù)庫成功删窒,發(fā)送一個數(shù)據(jù)庫更新的信號
    }
    return result;
}

2.刪:

刪除RSContactModel表中uid字段值為testUid的記錄

    BOOL result = [[RSDBService db] deleteObjectsFromTable:NSStringFromClass([RSContactModel class]) where: RSContactModel.uid.is(testUid)];

3.改:

以下事例為刪除某個uid為uid值的好友關系的時候裂垦,將contactModel中的delFlag更新為已刪除的代碼。實際上就是更新該記錄中的delFlag的字段

- (BOOL)deleteContactWithUid:(long long)uid {
    RSContactModel *contactModel = [[RSContactModel alloc] init];
    contactModel.delFlag = RSenDelFlag_DelflagNotExist;
    BOOL result = [[RSDBService db] updateRowsInTable:NSStringFromClass([RSContactModel class]) onProperty:RSContactModel.delFlag withObject:contactModel where:RSContactModel.uid.is(uid)];
    if (result) {
        [self.updateSignal sendNext:@(YES)];
        //如果result為true表示修改數(shù)據(jù)庫成功肌索,發(fā)送一個數(shù)據(jù)庫更新的信號
    }
    return result;
}

4.查:

數(shù)據(jù)庫查詢的接口就更多了蕉拢,這里舉例為根據(jù)uid的array查詢表中uid為array中的值的記錄。

-(NSArray<RSContactModel *>*)getContactsByUids:(NSArray *)uids {
    NSArray *tmp = [[RSDBService db] getObjectsOfClass:[RSContactModel class] fromTable:NSStringFromClass([RSContactModel class]) where:RSContactModel.uid.in(uids)];
    return tmp;
}

  • 事務transaction

WCDB的事務有兩種寫法诚亚,一種是通過block來實現(xiàn)晕换,另一種是通過獲取WCTTransaction來實現(xiàn),block的方式使用更簡單亡电,但是WCTTransaction的方式更易于傳遞佩抹。

//Block的方式
BOOL commited = [[RSDBService db] runTransaction:^BOOL{
    [[RSDBService db] insertObject:contact into:NSStringFromClass([RSContactModel class])];
    return YES;
}];

//WCTTransaction方式
WCTTransaction *transaction = [[RSDBService db] getTransaction];
BOOL result = [transaction begin];
[[RSDBService db] insertObject:contact into:NSStringFromClass([RSContactModel class])];
result = [transaction commit];
if(!result) {
    NSLog(@"%@",[transaction getError]);
}

擴展閱讀

微信移動端數(shù)據(jù)庫組件WCDB系列(一)-iOS基礎篇

微信移動端數(shù)據(jù)庫組件WCDB系列(二) — 數(shù)據(jù)庫修復三板斧

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粥庄,一起剝皮案震驚了整個濱河市建丧,隨后出現(xiàn)的幾起案子椰憋,更是在濱河造成了極大的恐慌,老刑警劉巖或辖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瘾英,死亡現(xiàn)場離奇詭異,居然都是意外死亡颂暇,警方通過查閱死者的電腦和手機缺谴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耳鸯,“玉大人湿蛔,你說我怎么就攤上這事膀曾。” “怎么了阳啥?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵添谊,是天一觀的道長。 經(jīng)常有香客問我察迟,道長斩狱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任扎瓶,我火速辦了婚禮所踊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘概荷。我一直安慰自己秕岛,他們只是感情好,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布乍赫。 她就那樣靜靜地躺著瓣蛀,像睡著了一般陆蟆。 火紅的嫁衣襯著肌膚如雪雷厂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天叠殷,我揣著相機與錄音改鲫,去河邊找鬼。 笑死林束,一個胖子當著我的面吹牛像棘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播壶冒,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼缕题,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了胖腾?” 一聲冷哼從身側(cè)響起烟零,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎咸作,沒想到半個月后锨阿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡记罚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年墅诡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桐智。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡末早,死狀恐怖烟馅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情然磷,我是刑警寧澤焙糟,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站样屠,受9級特大地震影響穿撮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜痪欲,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一悦穿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧业踢,春花似錦栗柒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至雇锡,卻和暖如春逛钻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锰提。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工曙痘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人立肘。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓边坤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谅年。 傳聞我的和親對象是個殘疾皇子茧痒,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當在唯一索引所對應的列上鍵入重復值時,會觸發(fā)此異常融蹂。 O...
    我想起個好名字閱讀 5,257評論 0 9
  • 關于Mongodb的全面總結(jié) MongoDB的內(nèi)部構造《MongoDB The Definitive Guide》...
    中v中閱讀 31,913評論 2 89
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,846評論 25 707
  • 發(fā)現(xiàn)其實我根本不懂愛旺订,我要的愛是對方要包容我的各方面,無條件的接受我殿较,這很難吧耸峭,我都不能包容自己,不然也就不會總是...
    珍眼看世界閱讀 208評論 0 1
  • 婁底書畫古玩城閱讀 262評論 0 0