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好的存在咱们也是确定须要掌握的!