WCDB使用文档

使用简介
iOS 官方使用教程
从FMDB迁移到WCDB

基本特性

  • 易用,WCDB支持一句代码即可将数据取出并组合为object。

  • WINQ(WCDB语言集成查询):通过WINQ,开发者无须为了拼接SQL的字符串而写一大坨胶水代码。

  • ORM(Object Relational Mapping):在WCDB内,ORM(Object Relational Mapping)是指

    将一个ObjC的类,映射到数据库的表和索引;
    将类的property,映射到数据库表的字段;

  • 高效,WCDB通过框架层和sqlcipher源码优化,使其更高效的表现。

  • 多线程高并发:WCDB支持多线程读与读、读与写并发执行,写与写串行执行。

  • 完整,WCDB覆盖了数据库相关各种场景的所需功能。
    加密:WCDB提供基于SQLCipher的数据库加密。
    损坏修复:WCDB内建了Repair Kit用于修复损坏的数据库。
    反注入:WCDB内建了对SQL注入的保护。


WCDB需要对其建模,一个model可以遵守WCTTableCoding协议并用一些宏,用于定义数据库索引、约束等.

//Message.h
@interface Message : NSObject 

@property int localID;
@property(retain) NSString *content;
@property(retain) NSDate *createTime;
@property(retain) NSDate *modifiedTime;

WCDB_PROPERTY(localID)
WCDB_PROPERTY(content)
WCDB_PROPERTY(createTime)
WCDB_PROPERTY(modifiedTime)

@end

//Message.mm
@implementation Message

WCDB_IMPLEMENTATION(Message)
WCDB_SYNTHESIZE(Message, localID)
WCDB_SYNTHESIZE(Message, content)
WCDB_SYNTHESIZE(Message, createTime)
WCDB_SYNTHESIZE_COLUMN(Message, modifiedTime, "db_modifiedTime")

WCDB_PRIMARY_AUTO_INCREMENT(Message, localID)
WCDB_INDEX(Message, "_index", createTime)

@end

其中:

WCDB_IMPLEMENTATION(className)用于定义进行绑定的类
WCDB_PROPERTY(propertyName)和WCDB_SYNTHESIZE(className, propertyName)用于声明和定义字段。
WCDB_PRIMARY_AUTO_INCREMENT(className, propertyName)用于定义主键且自增。
WCDB_INDEX(className, indexNameSubfix, propertyName)用于定义索引。

虽然WCDB多了一步ORM的操作,但这是一劳永逸的,并且会给我们后续的使用带来很大的便利。

经过ORM的类,大部分操作都只需要一行代码即可完成。

安装

1 安装CocoaPods.
2 Podfile里面写 pod 'WCDB'
3 pod install
4 安装好后编译一下

  • 注意: 由于WCDB是结合c++写的,引用#import 的文件.m里面都要改成.mm后缀的,所以一般上为了隔离model,不让view喝viewController里面也改成.mm后缀的,我们写一个model的分类,遵守WCTTableCoding协议并写WCDB_PROPERTY(),WCDB编译后项目里有快捷创建model类,直接创建出分类.
  • command + n 弹出窗口,我们拉到下面,发现有WCDB一栏,选择TableCodeable


    屏幕快照 2018-04-02 下午7.33.08.png
  • 生成的一个model类和一个model类的分类


    屏幕快照 2018-04-02 下午7.34.37.png

- SZYMessage.h文件
#import 

@interface SZYMessage : NSObject

@property(nonatomic, copy) NSString *name;
@property(nonatomic, assign) NSInteger localID;
@property(nonatomic, assign) float totalScore;
@property(nonatomic, strong) NSDate *createDate;

@end

- SZYMessage.m文件
#import "SZYMessage+WCTTableCoding.h"
#import "SZYMessage.h"
#import 

@implementation SZYMessage
//WCDB_IMPLEMENTATION,用于在类文件中定义绑定到数据库表的类
WCDB_IMPLEMENTATION(SZYMessage)
//WCDB_SYNTHESIZE,用于在类文件中定义绑定到数据库表的字段
WCDB_SYNTHESIZE(SZYMessage, name)
WCDB_SYNTHESIZE(SZYMessage, localID)


//默认使用属性名作为数据库表的字段名。对于属性名与字段名不同的情况,可以使用WCDB_SYNTHESIZE_COLUMN(className, propertyName, columnName)进行映射。
WCDB_SYNTHESIZE_COLUMN(SZYMessage, totalScore, "db_totalScore")

WCDB_SYNTHESIZE_DEFAULT(SZYMessage, createDate, WCTDefaultTypeCurrentDate) //设置一个默认值

//主键
WCDB_PRIMARY_ASC_AUTO_INCREMENT(SZYMessage, localID)
//用于定义非空约束
WCDB_NOT_NULL(SZYMessage, name)

@end

- SZYMessage+WCTTableCoding.h 文件

#import "SZYMessage.h"
#import 

@interface SZYMessage (WCTTableCoding) 
//WCDB_PROPERTY用于在头文件中声明绑定到数据库表的字段,写在分类里,不写在.h里面,这样view和controller不会 引入导入的文件

WCDB_PROPERTY(name)
WCDB_PROPERTY(localID)
WCDB_PROPERTY(totalScore)
WCDB_PROPERTY(createDate)

@end

下面我们开始创建数据库和表,并进行增删改查


##### 创建数据库和表
- (BOOL)creatDatabaseAndTable {
    //数据库路径
    NSString *path = [self.baseDirectory stringByAppendingPathComponent:@"SampleDB"];
    //NSLog(@"path--> %@",path);
    //创建数据库 路径一样,  该接口使用的是IF NOT EXISTS的SQL,因此可以用重复调用
    WCTDatabase *database = [[WCTDatabase alloc] initWithPath:path];
    _database = database;
    if ([database canOpen]) {
        NSLog(@"创建数据库成功");
    }else{
        NSLog(@"创建数据库失败");
        return NO;
    }

    
    //创建表  注:该接口使用的是IF NOT EXISTS的SQL,因此可以用重复调用。不需要在每次调用前判断表或索引是否已经存在。
    BOOL result = [database createTableAndIndexesOfName:SZY_TABLE_MESSAGE_NAME withClass:SZYMessage.class];

    if (!result) {
        NSLog(@"创建表失败");
        return NO;
    }
    return YES;
}


##### 插入单个数据
- (BOOL)insertData:(SZYMessage *)message {
    BOOL result = [_database insertObject:message into:SZY_TABLE_MESSAGE_NAME];
    
    //关闭数据库,_database如果能自己释放的话,会自动关闭,就不用手动调用关闭了
    [_database close];

    if (!result) {
        NSLog(@"插入失败");
        return NO;
    }else{
        NSLog(@"插入成功");
        return YES;
    }
}

    //插入多个数据: 
    BOOL result = [_database insertObject:message into:SZY_TABLE_MESSAGE_NAME];

    //增删改查用下面方法,可以链式调用

/*
    WCTInsert
     WCTDelete
     WCTUpdate
     WCTSelect
 */
     WCTInsert *insert = [_database prepareInsertObjectsOfClass:SZYMessage.class
                                                              into:SZY_TABLE_MESSAGE_NAME];
    BOOL result = [insert executeWithObjects:objects];


##### 查询数据  用localID排序
- (void)selectOrder {
    NSArray *objects2 = [_database getObjectsOfClass:SZYMessage.class fromTable:SZY_TABLE_MESSAGE_NAME orderBy:SZYMessage.localID.order()];
    [objects2 enumerateObjectsUsingBlock:^(SZYMessage *obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"用localID排序 --> %@ ",obj);
    }];
}

//查询数据  指定范围
- (void)selectCertainRange {
    NSArray *objects3 = [_database getObjectsOfClass:SZYMessage.class fromTable:SZY_TABLE_MESSAGE_NAME where:SZYMessage.localID.between(0,1) || SZYMessage.name.like(@"lil%")];
    [objects3 enumerateObjectsUsingBlock:^(SZYMessage *obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"objects3 --> %@ ",obj);
    }];
}

//定向 将查询的totalScore值赋给新创建的对象
- (void)selectAndAssignment {
    SZYMessage *message5 = [_database getOneObjectOnResults:SZYMessage.totalScore.max().as(SZYMessage.totalScore) fromTable:SZY_TABLE_MESSAGE_NAME];
    message5.localID = 5;
    NSLog(@"message5 --> %@ ",message5);
}

//链式调用
- (void)selectChain {
    //所有的对象
    WCTSelect *select = [_database prepareSelectObjectsOfClass:SZYMessage.class fromTable:SZY_TABLE_MESSAGE_NAME ];

    //链式查询
    NSArray *objects6 = [[select where:SZYMessage.totalScore < 90] limit:2].allObjects;
    [objects6 enumerateObjectsUsingBlock:^(SZYMessage *obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"objects6 --> %@ ",obj);
    }];
}


##### 更新
- (void)updateData {
    WCTUpdate *update = [_database prepareUpdateTable:SZY_TABLE_MESSAGE_NAME
                                        onProperties:SZYMessage.name];
    SZYMessage *object = [[SZYMessage alloc] init];
    object.name = @"xiaoming22";
    BOOL result = [update executeWithObject:object];
    if (!result) {
        NSLog(@"Update by object Error %@", update.error);
    }else{
        NSLog(@"更新成功");
    }
}


//删除表
- (void)deleteData {
    WCTDelete *deletion = [_database prepareDeleteFromTable:SZY_TABLE_MESSAGE_NAME];
    BOOL result = [deletion execute];
    if (!result) {
        NSLog(@"Delete Error %@", deletion.error);
    }else{
        NSLog(@"删除成功");
    }

    [_database close];
    //删除name是xiaoming的人
//    BOOL result = [_database deleteObjectsFromTable:SZY_TABLE_MESSAGE_NAME where:SZYMessage.name == @"xiaoming"];
//    [_database deleteObjectsFromTable:SZY_TABLE_MESSAGE_NAME where:SZYMessage.localID.between(0,1) || SZYMessage.name.like(@"lil%")];
    
}

Transaction(事务)

WCDB内可通过两种方式执行Transaction(事务),一是runTransaction:接口

//事务
- (void)transactionUseBlock {
//    blocked 方式用事务
    BOOL committed = [_database runTransaction:^BOOL{
        SZYMessage *object = [[SZYMessage alloc] init];

        BOOL result = [_database insertObject:object
                                     into:SZY_TABLE_MESSAGE_NAME];
        //return YES to do a commit and return NO to do a rollback
        if (result) {
            return YES;
        }
        return NO;
    } event:^(WCTTransactionEvent event) {
        NSLog(@"Event %d", event);
    }];
    
}

//不用block方式事务
- (void)transaction {
    BOOL result = [_database beginTransaction];
    SZYMessage *object = [[SZYMessage alloc] init];
    result = [_database insertObject:object
                            into:SZY_TABLE_MESSAGE_NAME];
    if (result) {
        result = [_database commitTransaction];
    } else {
        result = [_database rollbackTransaction];
    }
}

WINQ

上述例子中的一些特殊语法:

where:Message.localID>0
onProperties:Message.content
orderBy:Message.localID.order(WCTOrderedDescending) 这个便是WINQ。

WINQ(WCDB Integrated Query,音'wink'),即WCDB集成查询,是将自然查询的SQL集成到WCDB框架中的技术,基于C++实现。

传统的SQL语句,通常是开发者拼接字符串完成。这种方式不仅繁琐、易错,而且出错后很难定位到问题所在。同时也容易给SQL注入留下可乘之机。
下面是几个官方文档的例子

屏幕快照 2018-04-02 下午8.00.09.png
屏幕快照 2018-04-02 下午8.00.16.png

WINQ的接口包括但不限于:

一元操作符:+、-、!等
二元操作符:||、&&、+、-、*、/、|、&、<<、>>、<、<=、==、!=、>、>=等
范围比较:IN、BETWEEN等
字符串匹配:LIKE、GLOB、MATCH、REGEXP等
聚合函数:AVG、COUNT、MAX、MIN、SUM等
...

凡是SQLite支持的语法规则,WINQ基本都有其对应的接口。且接口名称与SQLite的语法规则基本保持一致。对于熟悉SQL的开发者,无须特别学习即可立刻上手使用。

链式调用

链式调用是指对象的接口返回一个对象,从而允许在单个语句中将调用链接在一起,而不需要变量来存储中间结果。

WCDB对于增删改查操作,都提供了对应的类以实现链式调用

WCTInsert
WCTDelete
WCTUpdate
WCTSelect
WCTRowSelect
WCTMultiSelect

where、orderBy、limit等接口的返回值均为self,因此可以通过链式调用,更自然更灵活的写出对应的查询。


屏幕快照 2018-04-02 下午8.03.07.png

你可能感兴趣的:(WCDB使用文档)