从FMDB到WCDB、微信团队怎么说?
WCDB背景
自己初次见到WCDB是微信开发团队公众号在今年五月份推送的一篇文章中(开发者团队的微信号上面图片中有,值得大家关注一下),那时候就说在筹备着WCDB的开源,觉得很是新奇,在两个多月前WCDB开源了!自己是最近才有时间看的WCDB,总结一下自己的理解和学习的东西,WCDB是微信团队开源的支持Android,也支持iOS,那当然也是会支持macOS的一个移动端数据库框架,FMDB估计做iOS的99.99%的都知道,就像Android开发中使用LitePal一样,都是在SQLite的基础上封装的移动数据库框架,WCDB是微信团队提供一个高效、易用、完整的移动端存储方案。 它包含三个模块:
1、WCDB-iOS/Mac
2、WCDB-Android
3、数据库损坏修复工具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类字段绑定的过程:
1、定义该类遵守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之后,你编译一下你的项目,你就可以看到上面我们说的模板文件,如下所示:
2、使用WCDB_PROPERTY宏在头文件声明需要绑定到数据库表的字段(也就是把你的表里面需要的字段在这里用这宏声明一次)
3、使用WCDB_IMPLEMENTATIO宏在类文件定义绑定到数据库表的类(把这个类绑定到数据库的表,你会在下面创建数据库的时候创建相应的表,表会和类绑定)
4、使用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操作的代码放出来,我们说的也知识基本的,要是想灵活应用还是得慢慢学,掌握它。
1、 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;
}
2、利用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。
2、损坏修复
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];
});
3、性能数据
为了测试WCDB的性能数据,WCDB提供了benchmark,用于横向比较FMDB、纵向比较不同的参数配置,并可用于验证后续更多性能优化的效果。这里吧官方的文档给大家,有需要有兴趣的可以看看,这部分的内容以及下面从FMDB迁移到WCDB的内容我们会抓们整理出来,因为项目我也准备迁移到WCDB,等搞定会把相应新的分享出来。
这部分的内容上面提到自己在准备迁移到WCDB,所以就等迁移完成了会分享出心得。
上面的内容其实都是一些WCDB最基本的使用,也是希望WCDB大家都能掌握,既然是比FMDB好的存在我们也是肯定需要掌握的!
从FMDB到WCDB、微信团队怎么说?的更多相关文章
- 微信团队分享:Kotlin渐被认可,Android版微信的技术尝鲜之旅
本文由微信开发团队工程是由“oneliang”原创发表于WeMobileDev公众号,内容稍有改动. 1.引言 Kotlin 是一个用于现代多平台应用的静态编程语言,由 JetBrains 开发( ...
- 微信团队分享:iOS版微信的高性能通用key-value组件技术实践
本文来自微信开发团队guoling的技术分享. 1.前言 本文要分享的是iOS版微信内部正在推广和使用的一个高性能通用key-value 组件的技术实践过程,该组件在微信内部被命名为MMKV(以下简称 ...
- 微信团队分享:iOS版微信是如何防止特殊字符导致的炸群、APP崩溃的?
本文来自微信开发团队yanyang的技术分享. 1.引言 相信大家都遇到过一段特殊文本可以让iOS设备所有app闪退的经历.前段时间大年初一,又出现某个印度语字符引起iOS11系统奔溃,所幸iOS版微 ...
- 微信团队原创分享:iOS版微信的内存监控系统技术实践
本文来自微信开发团队yangyang的技术分享. 一.前言 FOOM(Foreground Out Of Memory),是指App在前台因消耗内存过多引起系统强杀.对用户而言,表现跟crash一样. ...
- 微信团队分享:极致优化,iOS版微信编译速度3倍提升的实践总结
1.引言 岁月真是个养猪场,这几年,人胖了,微信代码也翻了. 记得 14 年转岗来微信时,用自己笔记本编译微信工程才十来分钟.如今用公司配的 17 年款 27-inch iMac 编译要接近半小时:偶 ...
- 微信开源组件WCDB漫谈及Demo
代码地址如下:http://www.demodashi.com/demo/12422.html 前言 移动端的数据库选型一直是一个难题,直到前段时间看到了WeMobileDev(微信前端团队)放出了第 ...
- 如何开发一款堪比APP的微信小程序(腾讯内部团队分享)
一夜之间,微信小程序刷爆了行业网站和朋友圈,小程序真的能如张小龙所说让用户"即用即走"吗? 其功能能和动辄几十兆安装文件的APP相比吗? 开发小程序,是不是意味着移动应用开发的一次 ...
- 【沙龙报名中】与微信&云开发官方团队零距离互动,揭秘爆款微信小游戏背后的技术!
有人说 微信小程序游戏的百花齐放 活像十几年前的4399小游戏称霸互联网的景象 " 歪,斗地主吗,三缺二, 不用下app,小程序就能玩,我保证不抢地主让你抢!" ...... &q ...
- 【转】手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)
1.引言 特别说明:本文内容仅用于即时通讯技术研究和学习之用,请勿用于非法用途.如本文内容有不妥之处,请联系JackJiang进行处理! 我司有关部门为了获取黑产群的动态,有同事潜伏在大量的黑产群 ...
随机推荐
- Django 踩过的坑(一)
平台:win10 工具:cmd python3 刚刚学习Django搭建环境,网站还木有发布,就直接来了个大麻烦. 一切按着<Django 学习笔记(二)>这篇文章来的,在最后cmd运行服 ...
- zookeeper初试
实验环境: os-platform: windows7 x64 jdk: 1.7 参考文档: http://www.ibm.com/developerworks/cn/opensource/os-cn ...
- log 的 debug()、 error()、 info()方法的区别
软件中总免不了要使用诸如 Log4net, Log4j, Tracer 等东东来写日志,不管用什么,这些东东大多是大同小异的,一般都提供了这样5个日志级别: × Debug × Info ...
- DotNetCore跨平台~EFCore连接Mysql的方式
回到目录 在.net frameworks的ef里连接mysql我们已经测试通过了,而在dotnet core里的efCore上去连接mysql我们需要测试一下,并且在测试过程中出现了一些问题,当然最 ...
- java基础系列--Exception异常处理
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/7191280.html 1.概述 Java代码中的异常处理是非常重要的一环,从代码中可以看到 ...
- js获取客户端MAC地址
最近遇到一个需求,医院要求呼叫中心账号必须对应MAC地址,也就是说该MAC地址必须和呼叫中心账号对应才可使用,这可就难道我了,这需求就要求每次都判断用户登录的电脑MAC地址是否有呼叫中心账号,当然只针 ...
- Python-WXPY实现微信监控报警
概述: 本文主要分享一下博主在学习wxpy 的过程中开发的一个小程序.博主在最近有一个监控报警的需求需要完成,然后刚好在学习wxpy 这个东西,因此很巧妙的将工作和学习联系在一起. 博文中主要使用到的 ...
- linux 的一些脑洞操作
把当前文件夹的文件名用","连接成一行,或者将多行转变为一行 ls | paste -s -d "," # -s 选项将输入进行一次性粘贴 ls | xargs ...
- Java IO 之 BIO、NIO、AIO
1.BIO.NIO.AIO解释 Java BIO : 同步并阻塞 (Blocking IO) 一个连接一个线程 即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不 ...
- ES6正则表达式扩展
前面的话 正则表达式是javascript操作字符串的一个重要组成部分,但在以往的版本中并未有太多改变.然而,在ES6中,随着字符串操作的变更, ES6也对正则表达式进行了一些更新.本文将详细介绍ES ...