WCDB学习与理解
简介
WCDB(WeChat DataBase)是微信官方的移动端数据库组件,它基于SQLCipher,是一个关系型数据库,支持iOS, macOS和Android。WCDB提供了三个基础类进行数据库操作:WCTDatabase、WCTTable、WCTTransaction。它们的接口都是线程安全的。WCDB几乎涵盖了常用的数据库操作,同时还开放了核心层接口,方便用户扩展一些未封装的复杂SQL操作。安全方面它继承了SQLCipher的加密方式,内建了Repair Kit用于修复损坏的数据库,通过内建宏的方式实现了ORM(Object Relational Mapping)
,方便地实现了对象属性到数据表字段的映射,通过一种名为WINQ
的规则对SQL进行了抽象,避免了冗长的SQL胶水代码,也防止了SQL注入。
ORM
WCDB使用内置的宏来连接类、属性与表、字段。共有三类宏,分别对应数据库的字段、索引和约束。所有宏都定义在WCTCodingMacro.h中。WCDB的ORM会自动识别property的类型,并映射到适合的数据库类型。其与Objective-C类型对应关系为:
- 整型
- NSDate(保存其时间戳)
- 浮点数
- NSNumber
- 字符串
- NSString、NSMutableString
- 二进制
- NSData、NSMutableData
- NSArray、NSMutableArray
- NSDictionary、NSMutableDictionary
- NSSet、NSMutableSet
- NSValue
- NSURL
关于ORM官方github文档给出了详细的中英文教程包括字段宏、索引宏、约束宏等在此不一一列举。
WINQ
WINQ避免了冗长复杂的SQL拼接操作,对SQL语句进行了抽象。抽象的思路还是从SQL语法规则出发,SQL的语法规则实则上是一种链式操作,可以理解为一些固定的keyword、object和expr的集合。所以WINQ的实现思路是将固定的keyword,封装为函数名,作为连接;将可以展开的token,封装为类,并在类内实现其不同的组合。这句话可能说的有点绕,通过下面的代码块可能比较好理解些。在下面的代码块中,把SELECT
定义成了一个类StatementSelect
,这个类有三个函数,函数名我们并不陌生,正是where
、limit
、having
三个SQL关键字,同时函数的返回也是一个StatementSelect对象,这样我们就能实现一种链式操作。实现了上面提到的连接
。另外我们可以发现三个函数还有一个共同点,它们的参数都是Expr类型,因为在实际的SQL语法规则中where、limit、having等操作都是接受表达式的,所以这里StatementSelect的类方法都是表达式。然后在Expr内部可以实现表达式的各种组合。1
2
3
4
5
6
7
8class StatementSelect : public Statement {
public:
//...
StatementSelect &where(const Expr &where);
StatementSelect &limit(const Expr &limit);
StatementSelect &having(const Expr &having);
//...
};
1 | class Expr : public Describable { |
基于这个抽象方式,就可以对复杂查询中的条件语句进行重写为:1
2
3
4
5
6
7
8
9
10
11
12
13Column content("content");
Column createTime("createTime");
Column modifiedTime("modifiedTime");
Column type("type");
StatementSelect select;
//...
//WHERE content IS NOT NULL
// AND createTime!=modifiedTime
// OR type NOT BETWEEN 0 AND 2
select.where(Expr(content).isNotNull()
&&Expr(createTime)!=Expr(modifiedTime)
||Expr(type).notBetween(0, 2));
//...
实践
建库
WCTDatabase表示一个数据库,可以进行所有数据库操作,包括增删查改、表操作、事务、文件操作、损坏修复等。对于同一个路径的数据库,不同的WCTDatabase、WCTTable、WCTTransaction对象共享同一个WCDB核心。因此,你可以在代码的不同位置、不同线程任意创建不同的基础类对象,WCDB会自动管理它们的共享数据和线程并发。1
2
3
4
5
6NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"test.db"];
_database = [[WCTDatabase alloc] initWithPath: path];
[_database close:^{
[_database removeFilesWithError:nil];
}];
建表
1 | if (![_database isTableExists:@"student"]) { |
数据操作
插入
1 | Student *student = [[Student alloc] init]; |
查询
1 | return [_database getOneObjectOfClass:Student.class |
总结
以上是我通读了WCDB的iOS官方文档和API做的一些总结,其中有一些自己的理解,同时也概括了WCDB的核心理念和使用方法。另外还有一些关于数据库修复、事务、约束的操作,没有详细列举。可以直接访问其github里面的中英文教程讲的非常详细。另外截止到2016年12月微信全球共计8.89亿月活用户,而新兴的公众号平台拥有1000万个,WCDB作为支撑这么一个平台的移动端数据库,其安全性和稳定性应该还是值得信赖的。如果是纯OC的项目,如果觉得CoreData学习成本高,不容易掌握,不是很稳定的话,推荐可以使用WCDB,但是项目中所有用到WCDB依赖的类实现文件都必须改成.mm
的形式。但如果是Swift或者OC/Swift混编项目,WCDB目前对Swift还不是很友好,希望WCDB团队后续能对Swift进行支持吧。
现在,WCDB的Swift版本已经发布了,官方wiki地址:关于 WCDB Swift