WCDB使用文檔

使用簡介
iOS 官方使用教程
從FMDB遷移到WCDB

基本特性

  • 易用,WCDB支持一句代碼即可將數(shù)據(jù)取出并組合為object涌萤。

  • WINQ(WCDB語言集成查詢):通過WINQ淹遵,開發(fā)者無須為了拼接SQL的字符串而寫一大坨膠水代碼。

  • ORM(Object Relational Mapping):在WCDB內负溪,ORM(Object Relational Mapping)是指

    將一個ObjC的類透揣,映射到數(shù)據(jù)庫的表和索引;
    將類的property川抡,映射到數(shù)據(jù)庫表的字段辐真;

  • 高效,WCDB通過框架層和sqlcipher源碼優(yōu)化猖腕,使其更高效的表現(xiàn)拆祈。

  • 多線程高并發(fā):WCDB支持多線程讀與讀、讀與寫并發(fā)執(zhí)行倘感,寫與寫串行執(zhí)行放坏。

  • 完整,WCDB覆蓋了數(shù)據(jù)庫相關各種場景的所需功能老玛。
    加密:WCDB提供基于SQLCipher的數(shù)據(jù)庫加密淤年。
    損壞修復:WCDB內建了Repair Kit用于修復損壞的數(shù)據(jù)庫钧敞。
    反注入:WCDB內建了對SQL注入的保護。


WCDB需要對其建模麸粮,一個model可以遵守WCTTableCoding協(xié)議并用一些宏,用于定義數(shù)據(jù)庫索引溉苛、約束等.

//Message.h
@interface Message : NSObject <WCTTableCoding>

@property int localID;
@property(retain) NSString *content;
@property(retain) NSDate *createTime;
@property(retain) NSDate *modifiedTime;

WCDB_PROPERTY(localID)
WCDB_PROPERTY(content)
WCDB_PROPERTY(createTime)
WCDB_PROPERTY(modifiedTime)

@end

//Message.mm
@implementation Message

WCDB_IMPLEMENTATION(Message)
WCDB_SYNTHESIZE(Message, localID)
WCDB_SYNTHESIZE(Message, content)
WCDB_SYNTHESIZE(Message, createTime)
WCDB_SYNTHESIZE_COLUMN(Message, modifiedTime, "db_modifiedTime")

WCDB_PRIMARY_AUTO_INCREMENT(Message, localID)
WCDB_INDEX(Message, "_index", createTime)

@end

其中:

WCDB_IMPLEMENTATION(className)用于定義進行綁定的類
WCDB_PROPERTY(propertyName)和WCDB_SYNTHESIZE(className, propertyName)用于聲明和定義字段。
WCDB_PRIMARY_AUTO_INCREMENT(className, propertyName)用于定義主鍵且自增弄诲。
WCDB_INDEX(className, indexNameSubfix, propertyName)用于定義索引愚战。

雖然WCDB多了一步ORM的操作,但這是一勞永逸的齐遵,并且會給我們后續(xù)的使用帶來很大的便利寂玲。

經(jīng)過ORM的類,大部分操作都只需要一行代碼即可完成梗摇。

安裝

1 安裝CocoaPods.
2 Podfile里面寫 pod 'WCDB'
3 pod install
4 安裝好后編譯一下

  • 注意: 由于WCDB是結合c++寫的,引用#import <WCDB/WCDB.h>的文件.m里面都要改成.mm后綴的,所以一般上為了隔離model,不讓view喝viewController里面也改成.mm后綴的,我們寫一個model的分類,遵守WCTTableCoding協(xié)議并寫WCDB_PROPERTY(),WCDB編譯后項目里有快捷創(chuàng)建model類,直接創(chuàng)建出分類.
  • command + n 彈出窗口,我們拉到下面,發(fā)現(xiàn)有WCDB一欄,選擇TableCodeable


    屏幕快照 2018-04-02 下午7.33.08.png
  • 生成的一個model類和一個model類的分類


    屏幕快照 2018-04-02 下午7.34.37.png

- SZYMessage.h文件
#import <Foundation/Foundation.h>

@interface SZYMessage : NSObject

@property(nonatomic, copy) NSString *name;
@property(nonatomic, assign) NSInteger localID;
@property(nonatomic, assign) float totalScore;
@property(nonatomic, strong) NSDate *createDate;

@end

- SZYMessage.m文件
#import "SZYMessage+WCTTableCoding.h"
#import "SZYMessage.h"
#import <WCDB/WCDB.h>

@implementation SZYMessage
//WCDB_IMPLEMENTATION拓哟,用于在類文件中定義綁定到數(shù)據(jù)庫表的類
WCDB_IMPLEMENTATION(SZYMessage)
//WCDB_SYNTHESIZE,用于在類文件中定義綁定到數(shù)據(jù)庫表的字段
WCDB_SYNTHESIZE(SZYMessage, name)
WCDB_SYNTHESIZE(SZYMessage, localID)


//默認使用屬性名作為數(shù)據(jù)庫表的字段名伶授。對于屬性名與字段名不同的情況,可以使用WCDB_SYNTHESIZE_COLUMN(className, propertyName, columnName)進行映射违诗。
WCDB_SYNTHESIZE_COLUMN(SZYMessage, totalScore, "db_totalScore")

WCDB_SYNTHESIZE_DEFAULT(SZYMessage, createDate, WCTDefaultTypeCurrentDate) //設置一個默認值

//主鍵
WCDB_PRIMARY_ASC_AUTO_INCREMENT(SZYMessage, localID)
//用于定義非空約束
WCDB_NOT_NULL(SZYMessage, name)

@end

- SZYMessage+WCTTableCoding.h 文件

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

@interface SZYMessage (WCTTableCoding) <WCTTableCoding>
//WCDB_PROPERTY用于在頭文件中聲明綁定到數(shù)據(jù)庫表的字段,寫在分類里,不寫在.h里面,這樣view和controller不會 引入導入<WCDB/WCDB.h>的文件

WCDB_PROPERTY(name)
WCDB_PROPERTY(localID)
WCDB_PROPERTY(totalScore)
WCDB_PROPERTY(createDate)

@end

下面我們開始創(chuàng)建數(shù)據(jù)庫和表,并進行增刪改查


##### 創(chuàng)建數(shù)據(jù)庫和表
- (BOOL)creatDatabaseAndTable {
    //數(shù)據(jù)庫路徑
    NSString *path = [self.baseDirectory stringByAppendingPathComponent:@"SampleDB"];
    //NSLog(@"path--> %@",path);
    //創(chuàng)建數(shù)據(jù)庫 路徑一樣,  該接口使用的是IF NOT EXISTS的SQL,因此可以用重復調用
    WCTDatabase *database = [[WCTDatabase alloc] initWithPath:path];
    _database = database;
    if ([database canOpen]) {
        NSLog(@"創(chuàng)建數(shù)據(jù)庫成功");
    }else{
        NSLog(@"創(chuàng)建數(shù)據(jù)庫失敗");
        return NO;
    }

    
    //創(chuàng)建表  注:該接口使用的是IF NOT EXISTS的SQL亮蒋,因此可以用重復調用慎玖。不需要在每次調用前判斷表或索引是否已經(jīng)存在笛粘。
    BOOL result = [database createTableAndIndexesOfName:SZY_TABLE_MESSAGE_NAME withClass:SZYMessage.class];

    if (!result) {
        NSLog(@"創(chuàng)建表失敗");
        return NO;
    }
    return YES;
}


##### 插入單個數(shù)據(jù)
- (BOOL)insertData:(SZYMessage *)message {
    BOOL result = [_database insertObject:message into:SZY_TABLE_MESSAGE_NAME];
    
    //關閉數(shù)據(jù)庫,_database如果能自己釋放的話,會自動關閉,就不用手動調用關閉了
    [_database close];

    if (!result) {
        NSLog(@"插入失敗");
        return NO;
    }else{
        NSLog(@"插入成功");
        return YES;
    }
}

    //插入多個數(shù)據(jù): 
    BOOL result = [_database insertObject:message into:SZY_TABLE_MESSAGE_NAME];

    //增刪改查用下面方法,可以鏈式調用

/*
    WCTInsert
     WCTDelete
     WCTUpdate
     WCTSelect
 */
     WCTInsert *insert = [_database prepareInsertObjectsOfClass:SZYMessage.class
                                                              into:SZY_TABLE_MESSAGE_NAME];
    BOOL result = [insert executeWithObjects:objects];


##### 查詢數(shù)據(jù)  用localID排序
- (void)selectOrder {
    NSArray<SZYMessage *> *objects2 = [_database getObjectsOfClass:SZYMessage.class fromTable:SZY_TABLE_MESSAGE_NAME orderBy:SZYMessage.localID.order()];
    [objects2 enumerateObjectsUsingBlock:^(SZYMessage *obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"用localID排序 --> %@ ",obj);
    }];
}

//查詢數(shù)據(jù)  指定范圍
- (void)selectCertainRange {
    NSArray<SZYMessage *> *objects3 = [_database getObjectsOfClass:SZYMessage.class fromTable:SZY_TABLE_MESSAGE_NAME where:SZYMessage.localID.between(0,1) || SZYMessage.name.like(@"lil%")];
    [objects3 enumerateObjectsUsingBlock:^(SZYMessage *obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"objects3 --> %@ ",obj);
    }];
}

//定向 將查詢的totalScore值賦給新創(chuàng)建的對象
- (void)selectAndAssignment {
    SZYMessage *message5 = [_database getOneObjectOnResults:SZYMessage.totalScore.max().as(SZYMessage.totalScore) fromTable:SZY_TABLE_MESSAGE_NAME];
    message5.localID = 5;
    NSLog(@"message5 --> %@ ",message5);
}

//鏈式調用
- (void)selectChain {
    //所有的對象
    WCTSelect *select = [_database prepareSelectObjectsOfClass:SZYMessage.class fromTable:SZY_TABLE_MESSAGE_NAME ];

    //鏈式查詢
    NSArray<SZYMessage *> *objects6 = [[select where:SZYMessage.totalScore < 90] limit:2].allObjects;
    [objects6 enumerateObjectsUsingBlock:^(SZYMessage *obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"objects6 --> %@ ",obj);
    }];
}


##### 更新
- (void)updateData {
    WCTUpdate *update = [_database prepareUpdateTable:SZY_TABLE_MESSAGE_NAME
                                        onProperties:SZYMessage.name];
    SZYMessage *object = [[SZYMessage alloc] init];
    object.name = @"xiaoming22";
    BOOL result = [update executeWithObject:object];
    if (!result) {
        NSLog(@"Update by object Error %@", update.error);
    }else{
        NSLog(@"更新成功");
    }
}


//刪除表
- (void)deleteData {
    WCTDelete *deletion = [_database prepareDeleteFromTable:SZY_TABLE_MESSAGE_NAME];
    BOOL result = [deletion execute];
    if (!result) {
        NSLog(@"Delete Error %@", deletion.error);
    }else{
        NSLog(@"刪除成功");
    }

    [_database close];
    //刪除name是xiaoming的人
//    BOOL result = [_database deleteObjectsFromTable:SZY_TABLE_MESSAGE_NAME where:SZYMessage.name == @"xiaoming"];
//    [_database deleteObjectsFromTable:SZY_TABLE_MESSAGE_NAME where:SZYMessage.localID.between(0,1) || SZYMessage.name.like(@"lil%")];
    
}

Transaction(事務)

WCDB內可通過兩種方式執(zhí)行Transaction(事務),一是runTransaction:接口

//事務
- (void)transactionUseBlock {
//    blocked 方式用事務
    BOOL committed = [_database runTransaction:^BOOL{
        SZYMessage *object = [[SZYMessage alloc] init];

        BOOL result = [_database insertObject:object
                                     into:SZY_TABLE_MESSAGE_NAME];
        //return YES to do a commit and return NO to do a rollback
        if (result) {
            return YES;
        }
        return NO;
    } event:^(WCTTransactionEvent event) {
        NSLog(@"Event %d", event);
    }];
    
}

//不用block方式事務
- (void)transaction {
    BOOL result = [_database beginTransaction];
    SZYMessage *object = [[SZYMessage alloc] init];
    result = [_database insertObject:object
                            into:SZY_TABLE_MESSAGE_NAME];
    if (result) {
        result = [_database commitTransaction];
    } else {
        result = [_database rollbackTransaction];
    }
}

WINQ

上述例子中的一些特殊語法:

where:Message.localID>0
onProperties:Message.content
orderBy:Message.localID.order(WCTOrderedDescending) 這個便是WINQ。

WINQ(WCDB Integrated Query垛膝,音'wink')丁稀,即WCDB集成查詢线衫,是將自然查詢的SQL集成到WCDB框架中的技術惑折,基于C++實現(xiàn)惨驶。

傳統(tǒng)的SQL語句敞咧,通常是開發(fā)者拼接字符串完成休建。這種方式不僅繁瑣评疗、易錯百匆,而且出錯后很難定位到問題所在加匈。同時也容易給SQL注入留下可乘之機。
下面是幾個官方文檔的例子

屏幕快照 2018-04-02 下午8.00.09.png
屏幕快照 2018-04-02 下午8.00.16.png

WINQ的接口包括但不限于:

一元操作符:+、-偎球、!等
二元操作符:||衰絮、&&、+猫牡、-镊掖、*、/症虑、|谍憔、&习贫、<<千元、>>幸海、<、<=袜硫、==婉陷、!=官研、>戏羽、>=等
范圍比較:IN、BETWEEN等
字符串匹配:LIKE杏瞻、GLOB衙荐、MATCH忧吟、REGEXP等
聚合函數(shù):AVG、COUNT讹俊、MAX厕倍、MIN、SUM等
...

凡是SQLite支持的語法規(guī)則讹弯,WINQ基本都有其對應的接口。且接口名稱與SQLite的語法規(guī)則基本保持一致悲靴。對于熟悉SQL的開發(fā)者,無須特別學習即可立刻上手使用庇楞。

鏈式調用

鏈式調用是指對象的接口返回一個對象,從而允許在單個語句中將調用鏈接在一起临燃,而不需要變量來存儲中間結果膜廊。

WCDB對于增刪改查操作爪瓜,都提供了對應的類以實現(xiàn)鏈式調用

WCTInsert
WCTDelete
WCTUpdate
WCTSelect
WCTRowSelect
WCTMultiSelect

where铆铆、orderBy薄货、limit等接口的返回值均為self谅猾,因此可以通過鏈式調用,更自然更靈活的寫出對應的查詢坐搔。


屏幕快照 2018-04-02 下午8.03.07.png
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谤绳,隨后出現(xiàn)的幾起案子消略,更是在濱河造成了極大的恐慌瞎抛,老刑警劉巖桐臊,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異断凶,居然都是意外死亡伤提,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門认烁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肿男,“玉大人,你說我怎么就攤上這事却嗡〔芭妫” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵窗价,是天一觀的道長如庭。 經(jīng)常有香客問我,道長撼港,這世上最難降的妖魔是什么哟楷? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任挎狸,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘土榴。我一直安慰自己矢赁,他們只是感情好豺憔,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著褒纲,像睡著了一般彻秆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天鳖眼,我揣著相機與錄音,去河邊找鬼蜂厅。 笑死稠通,一個胖子當著我的面吹牛飞主,可吹牛的內容都是我干的筏餐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼贡歧,長吁一口氣:“原來是場噩夢啊……” “哼绍弟!你這毒婦竟也來了?” 一聲冷哼從身側響起瞻佛,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎笔喉,沒想到半個月后贫途,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體姨裸,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年慷垮,在試婚紗的時候發(fā)現(xiàn)自己被綠了芹血。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片说贝。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖血筑,靈堂內的尸體忽然破棺而出绘沉,到底是詐尸還是另有隱情煎楣,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布车伞,位于F島的核電站择懂,受9級特大地震影響,放射性物質發(fā)生泄漏另玖。R本人自食惡果不足惜困曙,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谦去。 院中可真熱鬧赂弓,春花似錦、人聲如沸哪轿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窃诉。三九已至杨耙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間飘痛,已是汗流浹背珊膜。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宣脉,地道東北人车柠。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像塑猖,于是被迫代替她去往敵國和親竹祷。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內容