WCDB背景html
本身初次見到WCDB是微信開發團隊公衆號在今年五月份推送的一篇文章中(開發者團隊的微信號上面圖片中有,值得你們關注一下),那時候就說在籌備着WCDB的開源,以爲非常新奇,在兩個多月前WCDB開源了!本身是最近纔有時間看的WCDB,總結一下本身的理解和學習的東西,WCDB是微信團隊開源的支持Android,也支持iOS,那固然也是會支持macOS的一個移動端數據庫框架,FMDB估計作iOS的99.99%的都知道,就像Android開發中使用LitePal同樣,都是在SQLite的基礎上封裝的移動數據庫框架,WCDB是微信團隊提供一個高效、易用、完整的移動端存儲方案。 它包含三個模塊:git
一、WCDB-iOS/Macgithub
二、WCDB-Androidsql
三、數據庫損壞修復工具WCDBRepair數據庫
iOS 數據庫框架對比分析 性能優化
一:關係型數據庫,表明有CoreData、FMDB等微信
CoreData:微信團隊在公衆號的文章中對它的總結是這樣:它是蘋果內建框架,和Xcode深度結合,能夠很方便進行ORM;但其上手學習成本較高,不容易掌握。穩定性也堪憂,很容易crash;多線程的支持也比較雞肋。微信開發
FMDB:它基於SQLite封裝,對於有SQLite和ObjC基礎的開發者來講,簡單易懂,能夠直接上手;而缺點也正是在此,FMDB只是將SQLite的C接口封裝成了ObjC接口,沒有作太多別的優化,即所謂的膠水代碼(Glue Code)。使用過程須要用大量的代碼拼接SQL、拼裝Object,並不方便多線程
二:key-value數據庫,表明有Realm、LevelDB、RocksDB等併發
微信團隊對上面的總結是這樣:因其在各平臺封裝、優化的優點,比較受移動開發者的歡迎。對於iOS開發者,key-value的實現直接易懂,能夠像使用NSDictionary同樣使用Realm。而且ORM完全,省去了拼裝Object的過程。但其對代碼侵入性很強,Realm要求類繼承RLMObject的基類。這對於單繼承的ObjC,意味着不能再繼承其餘自定義的子類。同時,key-value數據庫對較爲複雜的查詢場景也比較無力。
說說本身的理解:上面的像Realm、LevelDB、RocksDB等key - value 類型的這幾個框架我都沒有使用過,沒有什麼話語權,說說本身用過的,上面的CoreData和FMDB,我記得我去年有寫過一篇博客,就這二者之間的區別等等的作過總結,有興趣的能夠去翻翻之前的,我也記得唐巧哥之前在他的公衆號文章中也說過這事,就這二者之間仍是支持FMDB,固然我相信CoreData蘋果說不定哪天就讓它變得受人們青睞,但當前可能仍是作得不夠吧,因此你這樣看可能也就不難理解,一塊兒爲何那麼多人用FMDB,但確實也是有些場景中CoreData能作起來容易點的的不必定FMDB也容易,好比在兩張表之間創建聯繫的時候,CoreData就會相對容易一點,因此,就像微信團隊最後總結那那句同樣:各個方案都有其獨特的優點及劣勢,沒有最好的,只有最適合的。
你期盼的數據庫框架是什麼樣子的?
下面這一段內容我不知道有多少夥伴在微信開發團隊的公衆號當中看到過,我本身看完下面這段話的時候,以爲總結的每一句話都是開發者的心聲,也許看完這段話你也會和我同樣,更加期盼的想去看看WCDB:
高效;增刪改查的高效是數據庫最基本的要求。除此以外,咱們還但願可以支持多個線程高併發地操做數據庫,以應對微信頻繁收發消息的場景。
易用;這是微信開源的原則,也是WCDB的原則。SQLite本不是一個易用的組件:爲了完成一個查詢,每每咱們須要寫不少拼接字符串、組裝Object的膠水代碼。這些代碼冗長繁雜,並且容易出錯,咱們但願組件能統一完成這些任務。
完整;數據庫操做是一個複雜的場景,咱們但願數據庫組件能完整覆蓋各類場景。包括數據庫損壞、監控統計、複雜的查詢、反注入等。
初試WCDB- 理解ORM
下面的內容就從最基本的開始,從表的建立,到後面的CRUD的操做,以及再到後面一些高級的用法全都過一遍,在這當中涉及到的問題,有些可能會給鏈接你們能夠本身去學習理解,有些我會說書我本身的理解,WCDB咱們上路......
安裝WCDB,在Wiki裏面說的也比較完整,這裏咱們就不在多說,直接使用CocoaPods直接安裝便可。
想理解WCDB須要先理解最基本的這個概念 ORM ,你們能夠點進去看看微信給的使用說明,咱們接着說:
在咱們的Demo中,咱們建立一個Message類,而後在這個類中聲明咱們須要的一些屬性:
上面文件你們看到了這個Message+WCTTableCoding.h ,看着很像是咱們經常使用的類別,其實就是,下面會說它的建立和做用,咱們在咱們的Message類中聲明咱們的屬性,而後至於爲何要把.m 後綴改爲.mm ,下面也會說,慢慢來。 下面就是咱們爲Message類創建ORM類字段綁定的過程:
一、定義該類遵照WCTTableCoding協議,能夠在類聲明上定義,也能夠經過文件模版在category內定義(下面具體說)。這裏推薦你們使用第二種,經過文件模板在category內定義,爲何要這樣作,就是爲了隔離Objective-C++代碼,WCDB基於WINQ,引入了Objective-C++代碼,因此對於引入了WCDB的源文件,都須要把後綴.m改成.mm,(這就是咱們上面改後綴的緣由)爲減小影響範圍,能夠經過Objective-C的category特性將其隔離,達到只在model層使用Objective-C++編譯,而不影響Controller和View。這一點在Wiki中是有提到的,
這樣作的好處是不知道你們都有沒有理解,這麼說,要是你經過第一種方法,不經過category定義,而是選擇了在類聲明中寫,這樣的話Message.h 中就須要有宏WCDB_PROPERTY,這樣你就在Message.h使用了WCDB的代碼,當你把Message.h在其餘Controller/View中引用的時候,那相應的Controller/View的.m就須要修改爲.mm 。形成沒必要要的工做,但你用第二種方法寫的時候,你就發如今Message.h中是沒有任何的關於WCDB的代碼的,後面你引用也不須要再去修改!但願你們理解這裏。
在你項目中你集成了WCDB以後,你編譯一下你的項目,你就能夠看到上面咱們說的模板文件,以下所示:
二、使用WCDB_PROPERTY宏在頭文件聲明須要綁定到數據庫表的字段(也就是把你的表裏面須要的字段在這裏用這宏聲明一次)
三、使用WCDB_IMPLEMENTATIO宏在類文件定義綁定到數據庫表的類(把這個類綁定到數據庫的表,你會在下面建立數據庫的時候建立相應的表,表會和類綁定)
四、使用WCDB_SYNTHESIZE宏在類文件定義綁定到數據庫表的類(第二步聲明瞭表須要的字段,第三步綁定了表中的類,第四步就等於把表和字段綁定)
根據上面的步驟,就簡單的完成了ORM的基本操做,想要了解更過的關於ORM宏的用法以及定義,仍是查看Wiki文檔:ORM使用教程
WCDB 初試 - CRUD
上面說完了ORM的操做,下面說說基本的數據庫的建立以及CRUD的操做,在說下面以前,咱們扯一點其餘的,不知道會不會有人不知道該怎樣去查看你創建的數據庫內容,這裏說推薦一個我本身一直在用的挺好用的工具 -- Navicat Premium ,你能夠點擊它去下載,提取密碼是 e73y 。固然這不是我提供的,是簡書同行提供的,謝謝無私奉獻!
下載下來以後你點擊安裝的時候可能還須要密碼:xclient.info
完了你打開,要是出現出損壞沒法使用,打不開的狀況,你須要設置:
注意: 要是你係統沒有這個任何來源,終端命令: sudo spctl --master-disable
經過上面的操做,相信應該沒什麼問題了,接着簡單一步帶過怎樣查看已有的數據庫的:
左上角 Connection 選擇 SQLite以下:
下面是正題,數據庫的建立:
-(BOOL)creatDataBaseWithName:(NSString *)tableName{ //獲取沙盒根目錄 NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; // 文件路徑 NSString *filePath = [documentsPath stringByAppendingPathComponent:@"model.sqlite"]; NSLog(@"path = %@",filePath); database = [[WCTDatabase alloc]initWithPath:filePath]; // 數據庫加密 //NSData *password = [@"MyPassword" dataUsingEncoding:NSASCIIStringEncoding]; //[database setCipherKey:password]; //測試數據庫是否可以打開 if ([database canOpen]) { // WCDB大量使用延遲初始化(Lazy initialization)的方式管理對象,所以SQLite鏈接會在第一次被訪問時被打開。開發者不須要手動打開數據庫。 // 先判斷表是否是已經存在 if ([database isOpened]) { if ([database isTableExists:tableName]) { NSLog(@"表已經存在"); return NO; }else // 建立方法 return [database createTableAndIndexesOfName:tableName withClass:Message.class]; } } return NO; }
下面是基本的增刪查改的操做,這裏寫的一些都是最基本最基本的,下面再說兩個基本的事務處理方法,而後再把CRUD操做的代碼放出來,咱們說的也知識基本的,要是想靈活應用仍是得慢慢學,掌握它。
一、 block處理事務,顧名思義就是把咱們的事務處理放在block當中,以下咱們舉的這個例子:
// 另外一種事務處理方法Block -(BOOL)insertMessageWithBlock{ BOOL commit = [database runTransaction:^BOOL{ BOOL ret = [self insertMessage]; if (ret) { return YES; }else return NO; } event:^(WCTTransactionEvent event) { NSLog(@"Event %d", event); }]; return commit; }
二、利用WCTTransaction來處理事務:
// WCTDatabase 事務操做,利用WCTTransaction -(BOOL)insertMessageWithTransaction{ BOOL ret = [database beginTransaction]; ret = [self insertMessage]; if (ret) { [database commitTransaction]; }else [database rollbackTransaction]; return ret; }
下面是咱們寫的簡單的一個CRUD的操做的代碼:
-(BOOL)insertMessage{ //插入 Message *message = [[Message alloc] init]; message.localID = 1; message.content = @"Hello, WCDB!"; message.createTime = [NSDate date]; message.modifiedTime = [NSDate date]; /* INSERT INTO message(localID, content, createTime, modifiedTime) VALUES(1, "Hello, WCDB!", 1496396165, 1496396165); */ return [database insertObject:message into:@"message"]; } -(BOOL)deleteMessage{ //刪除 //DELETE FROM message WHERE localID>0; return [database deleteObjectsFromTable:@"message" where:Message.localID > 0]; } -(BOOL)updataMessage{ //修改 //UPDATE message SET content="Hello, Wechat!"; Message *message = [[Message alloc] init]; message.content = @"Hello, Wechat!"; //下面這句在17號的時候和微信團隊的人在學習羣裏面溝經過,這個方法確實是不存在的,使用教程應該會更新,要是沒更新注意這個方法 //BOOL result = [database updateTable:@"message" onProperties:Message.content withObject:message]; return [database updateAllRowsInTable:@"message" onProperty:Message.content withObject:message]; } //查詢 -(NSArray *)seleteMessage{ //SELECT * FROM message ORDER BY localID NSArray<Message *> * message = [database getObjectsOfClass:Message.class fromTable:@"message" orderBy:Message.localID.order()]; return message; }
上面事務方面的暫時先說這麼多,固然這方面的內容能夠看具體的文檔: 基礎類、CRUD與Transaction
WCDB 其餘
WCDB提供了對錯誤和性能的全局監控,可用於調試錯誤和性能。 也能夠獲取某個特定操做的錯誤信息。全部錯誤都以WCTError的形式出現。WCTError 就是繼承自咱們常見的NSError。
二、損壞修復
WCDB內建了修復工具,以應對數據庫損壞,沒法使用的狀況。咱們須要在數據庫未損壞時,對數據庫元信息定時進行備份,以下:
NSData *backupPassword = [@"MyBackupPassword" dataUsingEncoding:NSASCIIStringEncoding]; [database backupWithCipher:backupPassword];
注意:當檢測到數據庫損壞,即WCTError的type爲WCTErrorTypeSQLite
,code爲11或26(SQLITE_CORRUPT或SQLITE_NOTADB)時,能夠進行修復,下面是官方給出的代碼示例:
//Since recovering is a long time operation, you'd better call it in sub-thread. [view startLoading]; dispatch_async(DISPATCH_QUEUE_PRIORITY_BACKGROUND, ^{ WCTDatabase *recover = [[WCTDatabase alloc] initWithPath:recoverPath]; NSData *password = [@"MyPassword" dataUsingEncoding:NSASCIIStringEncoding]; NSData *backupPassword = [@"MyBackupPassword" dataUsingEncoding:NSASCIIStringEncoding]; int pageSize = 4096;//Default to 4096 on iOS and 1024 on macOS. [database close:^{ [recover recoverFromPath:path withPageSize:pageSize backupCipher:cipher databaseCipher:password]; }]; [view stopLoading]; });
三、性能數據
爲了測試WCDB的性能數據,WCDB提供了benchmark,用於橫向比較FMDB、縱向比較不一樣的參數配置,並可用於驗證後續更多性能優化的效果。這裏吧官方的文檔給你們,有須要有興趣的能夠看看,這部分的內容以及下面從FMDB遷移到WCDB的內容咱們會抓們整理出來,由於項目我也準備遷移到WCDB,等搞定會把相應新的分享出來。
這部分的內容上面提到本身在準備遷移到WCDB,因此就等遷移完成了會分享出心得。
上面的內容其實都是一些WCDB最基本的使用,也是但願WCDB你們都能掌握,既然是比FMDB好的存在咱們也是確定須要掌握的!