WCDB漫談

前言

移動端的數(shù)據(jù)庫選型一直是一個難題唧席,直到前段時間看到了WeMobileDev(微信前端團隊)放出了第三個開源組件-WCDB

WCDB(WeChat DataBase)是微信官方的移動端數(shù)據(jù)庫組件擦盾,致力于提供一個高效嘲驾、易用、完整的移動端存儲方案

微信團隊怎么說

  • 基于SQLCipher

  • WCDB-iOS/Mac

  • WCDB-Android

  • 數(shù)據(jù)庫損壞修復(fù)工具WDBRepair

背景

WCDB的出現(xiàn)可以說解決了目前移動端數(shù)據(jù)庫的幾個難點

  • 首先在選型上迹卢,FMDB的SQL拼接辽故、難以防止的SQL注入;CoreData雖然可以方便ORM腐碱,但學(xué)習(xí)成本高誊垢,穩(wěn)定性堪憂,而且多線程雞肋症见;另外基于C語言的sqlite我想用的人也應(yīng)該不多喂走;除了上述關(guān)系型數(shù)據(jù)庫之外然后還有一些其他的Key-Value型數(shù)據(jù)庫,如我用過的Realm谋作,對于ObjC開發(fā)者來說芋肠,上手倒是沒什么難度,但缺點顯而易見遵蚜,需要繼承帖池,入侵性強,對于單繼承的OC來說這并不理想吭净,而且對于集合類型不完全支持睡汹,復(fù)雜查詢也比較無力。
  • 高效
    • 多線程高并發(fā):WCDB支持多線程讀與讀寂殉、讀與寫并發(fā)執(zhí)行帮孔,寫與寫串行執(zhí)行。

    • 批量寫操作性能測試:

      批量寫 ops/sec
      WCDB 458000
      FMDB 161000
  • 易用 WCDB支持一句代碼即可將數(shù)據(jù)取出并組合為object
    • WINQ(WCDB語言集成查詢):通過WINQ不撑,開發(fā)者無須為了拼接SQL的字符串而寫一大坨膠水代碼文兢。

    • ORM(Object Relational Mapping):WCDB支持靈活、易用的ORM焕檬。開發(fā)者可以很便捷地定義表姆坚、索引、約束实愚,并進行增刪改查操作兼呵。

    • 像這樣

      [database getObjectsOfClass:WCTSampleConvenient.class
      
              fromTable:tableName 
              
              where:WCTSampleConvenient.intValue>=10 
              
              limit:20];
      
  • 完整
    • 加密:WCDB提供基于SQLCipher的數(shù)據(jù)庫加密。
    • 損壞修復(fù):WCDB內(nèi)建了Repair Kit用于修復(fù)損壞的數(shù)據(jù)庫腊敲。
    • WCDB提供接口直接獲取SQL的執(zhí)行耗時击喂,可用于監(jiān)控性能。
    • 反注入:WCDB內(nèi)建了對SQL注入的保護

ORM

在WCDB內(nèi)碰辅,ORM(Object Relational Mapping)是指

  • 將一個ObjC的類懂昂,映射到數(shù)據(jù)庫的表和索引;

  • 將類的property没宾,映射到數(shù)據(jù)庫表的字段凌彬;

這一過程沸柔。通過ORM,可以達到直接通過Object進行數(shù)據(jù)庫操作铲敛,省去拼裝過程的目的褐澎。

WCDB通過內(nèi)建的宏實現(xiàn)ORM的功能。如下

image
image

PS:但我不建議這么做伐蒋,首先要避免在.h文件中引用<WCDB/WCDB.h>,因為你一旦引用工三,就需要改變.m文件為.mm文件,因為WCDB是基于objectiveC++先鱼;你可以使用Category特性將其隔離俭正,在category中引用<WCDB/WCDB.h>,并遵守WCTTableCoding協(xié)議型型,使用WCDB_PROPERTY將聲明綁定到數(shù)據(jù)庫表的字段段审。然后在模型類中引用category全蝶。達到不印象Controller和View的目的闹蒜。這點官方wiki中也有提到,使用文件模板來創(chuàng)建抑淫。具體請見Demo

對于一個已有的ObjC類绷落,

  • 引用WCDB框架頭文件#import <WCDB/WCDB.h>,并定義類遵循WCTTableCoding協(xié)議

  • 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

得益于ORM的定義,WCDB可以直接進行通過object進行增刪改查(CRUD)操作哺窄。

  • //插入
    Person *man = [[Person alloc] init];
    man.isAutoIncrement = YES;
    man.name = @"Hello, WCDB!";
    man.age = 12;
    return  [database insertObject:man into:TABLE_WCDB_NAME];
    
  • return [database deleteObjectsFromTable:TABLE_WCDB_NAME where:Person.studentId == studentId];
    
  • Person *person = [[Person alloc] init];
    person.name = content;
    return [database updateRowsInTable:TABLE_WCDB_NAME onProperties:Person.name withObject:person where:Person.studentId == studentId];
    
  • NSArray<Person *> * person = [database getObjectsOfClass:Person.class fromTable:TABLE_WCDB_NAME orderBy:Person.localID.order()];
    

Transaction

WCDB內(nèi)可通過兩種方式執(zhí)行Transaction(事務(wù))捐下,一是runTransaction:接口

image

這種方式要求數(shù)據(jù)庫操作在一個BLOCK內(nèi)完成,簡單易用萌业。

另一種方式則是獲取WCTTransaction對象

image

WCTTransaction對象可以在類或函數(shù)間傳遞坷襟,因此這種方式也更具靈活性。

WINQ

WINQ(WCDB Integrated Query生年,音'wink')婴程,即WCDB集成查詢,是將自然查詢的SQL集成到WCDB框架中的技術(shù)抱婉,基于C++實現(xiàn)排抬。

  • 免去拼接SQL字符串懂从、防注入
  • 借助IDE代碼提示和編譯器語法檢查
  • 對于一個已綁定ORM的類,可以通過className.propertyName的方式蹲蒲,獲得數(shù)據(jù)庫內(nèi)字段的映射
  • WINQ的接口包括但不限于:
    • 一元操作符:+番甩、-、!等
    • 二元操作符:||届搁、&&缘薛、+、-卡睦、*宴胧、/、|表锻、&恕齐、<<、>>瞬逊、<显歧、<=、==确镊、!=士骤、>、>=等
    • 范圍比較:IN蕾域、BETWEEN等
    • 字符串匹配:LIKE拷肌、GLOB、MATCH旨巷、REGEXP等
    • 聚合函數(shù):AVG巨缘、COUNT、MAX采呐、MIN若锁、SUM等
    • ...

原理

  • 初衷,適應(yīng)WCDB+ORM解決SQL字符串的代碼冗余和難以被編譯器進行語法檢查而造成的錯誤和時間浪費懈万。SQL字符串太容易被注入
  • SQL抽象
  • 封裝常用操作拴清,覆蓋80%的使用場景
  • 暴露底層接口,適配剩余20%的特殊情況
  • 定義常用操作
  • 特殊場景所暴露的底層接口会通,應(yīng)該以什么形式存在口予?
  • SELECT、DISTINCT涕侈、ALL等等大寫字母是keyword沪停,屬于SQL的保留字。
  • result-column、``table-or-subquery木张、expr等等小寫字母是token众辨。token可以再進一步地展開其構(gòu)成的語法規(guī)則。
  • 將固定的keyword舷礼,封裝為函數(shù)名鹃彻,作為連接。
  • 將可以展開的token妻献,封裝為類蛛株,并在類內(nèi)實現(xiàn)其不同的組合。
  • 在語法規(guī)則中育拨,WHERE谨履、LIMIT等都接受expr作為參數(shù)。因此熬丧,不管SQL多么復(fù)雜笋粟,StatementSelect也只接受Expr的參數(shù)。而其組合的能力析蝴,則在Expr類內(nèi)實現(xiàn)害捕。

數(shù)據(jù)庫修復(fù)

  • 官方的Dump恢復(fù)方案
    • 遍歷sqlite_master表,將未損壞的表和已損壞的前半部分讀取出來將dump 出來的SQL語句逐行執(zhí)行嫌变,最終可以得到一個等效的新DB
      功率約為30%吨艇。
    • 第一頁就損壞后續(xù)無法讀取
  • 備份恢復(fù)方案
    • COPY
    • 在DB完好的時候執(zhí)行.dump
    • Backup API: SQLite自身提供的一套備份機制躬它,按 Page 為單位復(fù)制到新 DB腾啥, 支持熱備份。
    • 最終選擇Dump + 壓縮冯吓,恢復(fù)成功率達到72%
  • 解析B-tree恢復(fù)方案(RepairKit)
    • 成功率約為78%
  • 不同方案的組合
    • RepairKit 嘗試恢復(fù)最新數(shù)據(jù)
    • 備份恢復(fù) 遇到錯誤填補漏缺
    • Dump 最后的嘗試

For Android

  • 基本功能

    • 基于SQLCipher的數(shù)據(jù)庫加密
    • 使用連接池實現(xiàn)并發(fā)讀寫
    • 內(nèi)建 Repair Kit 可用于修復(fù)損壞數(shù)據(jù)
    • 針對占用空間大小優(yōu)化的數(shù)據(jù)庫備份/恢復(fù)功能
    • 日志輸出重定向以及性能跟蹤接口
    • 內(nèi)建用于全文搜索的 mmicu FTS3/4 分詞器
  • 接入與遷移

    • WCDB for Android 可通過 Maven 或 AAR 包引用倘待,API 接口與 Android SDK 非常相近, 所以將已有的 App 遷移到 WCDB 是相當(dāng)容易的组贺。
    • Android 接入與遷移
  • 數(shù)據(jù)庫修復(fù)

  • 從源碼編譯

    • 你可以使用預(yù)編譯的依賴庫(OpenSSL crypto 和 SQLCipher)來編譯 WCDB for Android凸舵, 使用 Gradle 或 Android Studio 皆可。Android Studio 請導(dǎo)入 android 目錄作為 Root Project失尖。
    • 編譯 WCDB 需要安裝 Android NDK r11c 或以上啊奄,并在 android/local.properties 上配置好 SDK 與 NDK 路徑。Android Studio 一般會幫你配置好掀潮。
    • 如果你需要自己編譯 OpenSSL 等依賴項菇夸,你需要一個 Bash 環(huán)境(Windows 可以安裝 Cygwin 或 MSys)、target 為本機的 C 編譯器(如 GCC)仪吧、Perl 5 以及 Tcl庄新。之后執(zhí)行下面命令即可編譯依賴項。

參考資料

Demo

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

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

微信移動端數(shù)據(jù)庫組件WCDB系列(三) — WINQ原理篇

微信移動數(shù)據(jù)庫組件WCDB(四) — Android 特性篇

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市择诈,隨后出現(xiàn)的幾起案子械蹋,更是在濱河造成了極大的恐慌,老刑警劉巖羞芍,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哗戈,死亡現(xiàn)場離奇詭異,居然都是意外死亡荷科,警方通過查閱死者的電腦和手機跪妥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來该面,“玉大人酣胀,你說我怎么就攤上這事∪龋” “怎么了煮剧?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長将鸵。 經(jīng)常有香客問我勉盅,道長,這世上最難降的妖魔是什么顶掉? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任草娜,我火速辦了婚禮,結(jié)果婚禮上痒筒,老公的妹妹穿的比我還像新娘宰闰。我一直安慰自己,他們只是感情好簿透,可當(dāng)我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布移袍。 她就那樣靜靜地躺著,像睡著了一般老充。 火紅的嫁衣襯著肌膚如雪葡盗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天啡浊,我揣著相機與錄音觅够,去河邊找鬼。 笑死巷嚣,一個胖子當(dāng)著我的面吹牛喘先,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涂籽,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼苹祟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起树枫,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤直焙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后砂轻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奔誓,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年搔涝,在試婚紗的時候發(fā)現(xiàn)自己被綠了厨喂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡庄呈,死狀恐怖蜕煌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诬留,我是刑警寧澤斜纪,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站文兑,受9級特大地震影響盒刚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜绿贞,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一因块、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧籍铁,春花似錦涡上、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歼冰。三九已至靡狞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間隔嫡,已是汗流浹背甸怕。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留腮恩,地道東北人梢杭。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像秸滴,于是被迫代替她去往敵國和親武契。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,500評論 2 359

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