WCDB
WCDB是一个高效、完整、易用的移动数据库框架,基于SQLCipher,支持iOS, macOS。
WCDB for iOS/macOS
基本特性
-
易用,WCDB支持一句代码即可将数据取出并组合为object。
-
WINQ(WCDB语言集成查询):通过WINQ,开发者无须为了拼接SQL的字符串而写一大坨胶水代码。
-
ORM(Object Relational Mapping):WCDB支持灵活、易用的ORM。开发者可以很便捷地定义表、索引、约束,并进行增删改查操作。
[database getObjectsOfClass:WCTSampleConvenient.class fromTable:tableName where:WCTSampleConvenient.intValue>=10 limit:20];
-
-
高效,WCDB通过框架层和sqlcipher源码优化,使其更高效的表现。
-
多线程高并发:WCDB支持多线程读与读、读与写并发执行,写与写串行执行。
-
批量写操作性能测试:
更多关于WCDB的性能数据,请参考benchmark。
-
-
完整,WCDB覆盖了数据库相关各种场景的所需功能。
- 加密:WCDB提供基于SQLCipher的数据库加密。
- 损坏修复:WCDB内建了Repair Kit用于修复损坏的数据库。
- 反注入:WCDB内建了对SQL注入的保护。
基本要求
- WCDB支持iOS 7、macOS 10.9以上。
- WCDB需使用Xcode 8.0以上版本进行编译。
- 需使用Objective-C++。
通过CocoaPods安装,此处不介绍安装过程,感兴趣可以参考文章:http://www.cnblogs.com/HJiang/p/7228166.html
/* 将一个已有的ObjC类进行ORM绑定的过程如下: 定义该类遵循WCTTableCoding协议。可以在类声明上定义,也可以通过文件模版在category内定义。 使用WCDB_PROPERTY宏在头文件声明需要绑定到数据库表的字段。 使用WCDB_IMPLEMENTATIO宏在类文件定义绑定到数据库表的类。 使用WCDB_SYNTHESIZE宏在类文件定义需要绑定到数据库表的字段。 */
.实体类.
新建Message类
Message.h
#import <Foundation/Foundation.h> @interface Message : NSObject /** * 本地id */ @property (nonatomic,assign) int localID; /** * 消息内容 */ @property (nonatomic, strong) NSString *content; /** * 创建时间 */ @property (nonatomic, strong) NSDate *createTime; /** * 最后更新时间 */ @property (nonatomic, strong) NSDate *modifiedTime; /** * 未读消息 */ @property (nonatomic,assign) int unused; @end
Message.mm
#import "Message.h" #import "Message+WCTTableCoding.h" @implementation Message // 利用这个宏定义绑定到表的类 WCDB_IMPLEMENTATION(Message) // 下面四个宏定义绑定到表中的字段 WCDB_SYNTHESIZE(Message, localID) WCDB_SYNTHESIZE(Message, content) WCDB_SYNTHESIZE(Message, createTime) WCDB_SYNTHESIZE(Message, modifiedTime) // 约束宏定义数据库的主键 WCDB_PRIMARY(Message, localID) // 定义数据库的索引属性,它直接定义createTime字段为索引 // 同时 WCDB 会将表名 + "_index" 作为该索引的名称 WCDB_INDEX(Message, "_index", createTime) - (NSString *)description{ return [NSString stringWithFormat:@"localID:%d content:%@ createTime:%@ modifiedTime:%@",_localID,_content,_createTime,_modifiedTime]; } @end
Message+WCTTableCoding.h Message分类
#import "Message.h" #import <WCDB/WCDB.h> @interface Message (WCTTableCoding) <WCTTableCoding> /* 需要绑定到表中的字段在这里声明,在.mm中去绑定 使用WCDB_PROPERTY宏在头文件声明需要绑定到数据库表的字段。 */ WCDB_PROPERTY(localID) WCDB_PROPERTY(content) WCDB_PROPERTY(createTime) WCDB_PROPERTY(modifiedTime) @end
由于WCDB是基于Objective-C++,因此需要将引用WCDB的源文件后缀.m
改为.mm
所以Message.m需修改为.mm
数据库管理类
WCTDatabaseManager.h WCTDatabaseManager.mm
#import <Foundation/Foundation.h> @class WCTDatabase; @interface WCTDatabaseManager : NSObject + (instancetype)shareInstance; - (WCTDatabase *)getDatabase; /** 创建数据库 @param tableName 表名称 @return 是否创建成功 */ - (BOOL)creatDataBaseWithName:(NSString *)tableName; @end
#import "WCTDatabaseManager.h" #import "WCTDatabaseManager+DataBase.h" #import "Message.h" //#import "Message+WCTTableCoding.h" @interface WCTDatabaseManager() { WCTDatabase *database; } @end @implementation WCTDatabaseManager + (instancetype)shareInstance{ static WCTDatabaseManager * instance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[WCTDatabaseManager alloc]init]; }); return instance; } - (NSString *)getDatabasePath{ //获取沙盒根目录 NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; // 文件路径 NSString *filePath = [documentsPath stringByAppendingPathComponent:@"Wechat.sqlite"]; return filePath; } - (WCTDatabase *)getDatabase{ if(!database){ NSString *filePath = [self getDatabasePath]; NSLog(@"wChatDatapath = %@",filePath); database = [[WCTDatabase alloc] initWithPath:filePath]; } return database; } -(BOOL)creatDataBaseWithName:(NSString *)tableName{ [self getDatabase]; // 数据库加密 //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; } @end
WCTDatabaseManager+DataBase.h WCTDatabaseManager分类,引入WCDB头文件
#import <WCDB/WCDB.h> @interface WCTDatabaseManager (DataBase) @end
数据库操作类
#import <Foundation/Foundation.h> @class Message; @interface MessageDao : NSObject - (BOOL)insertMessage:(Message *)message; - (BOOL)insertMessageWithTransaction:(Message *)message; - (BOOL)insertMessageWithBlock:(Message *)message; - (BOOL)deleteMessage:(Message *)message; - (BOOL)updataMessage:(Message *)message; - (NSArray *)seleteMessages; @end
#import "MessageDao.h" #import "WCTDatabaseManager.h" #import <WCDB/WCDB.h> #import "Message.h" #import "Message+WCTTableCoding.h" #define kDataBase [[WCTDatabaseManager shareInstance] getDatabase] @implementation MessageDao - (BOOL)insertMessage:(Message *)message{ return [kDataBase insertObject:message into:@"message"]; } // WCTDatabase 事务操作,利用WCTTransaction - (BOOL)insertMessageWithTransaction:(Message *)message{ BOOL ret = [kDataBase beginTransaction]; ret = [self insertMessage:message]; if (ret) { [kDataBase commitTransaction]; }else{ [kDataBase rollbackTransaction]; } return ret; } // 另一种事务处理方法Block - (BOOL)insertMessageWithBlock:(Message *)message{ BOOL commit = [kDataBase runTransaction:^BOOL{ BOOL ret = [self insertMessage:message]; if (ret) { return YES; }else{ return NO; } } event:^(WCTTransactionEvent event) { NSLog(@"Event %d", event); }]; return commit; } - (BOOL)deleteMessage:(Message *)message{ // 删除 //DELETE FROM message WHERE localID>0; return [kDataBase deleteObjectsFromTable:@"message" where:Message.localID > 0]; } - (BOOL)updataMessage:(Message *)message{ //修改 //UPDATE message SET content="Hello, Wechat!"; return [kDataBase updateAllRowsInTable:@"message" onProperty:Message.content withObject:message]; } - (NSArray *)seleteMessage{ //SELECT * FROM message ORDER BY localID NSArray<Message *> * message = [kDataBase getObjectsOfClass:Message.class fromTable:@"message" orderBy:Message.localID.order()]; return message; } @end
测试方法
---恢复内容结束---
WCDB
WCDB是一个高效、完整、易用的移动数据库框架,基于SQLCipher,支持iOS, macOS。
WCDB for iOS/macOS
基本特性
-
易用,WCDB支持一句代码即可将数据取出并组合为object。
-
WINQ(WCDB语言集成查询):通过WINQ,开发者无须为了拼接SQL的字符串而写一大坨胶水代码。
-
ORM(Object Relational Mapping):WCDB支持灵活、易用的ORM。开发者可以很便捷地定义表、索引、约束,并进行增删改查操作。
[database getObjectsOfClass:WCTSampleConvenient.class fromTable:tableName where:WCTSampleConvenient.intValue>=10 limit:20];
-
-
高效,WCDB通过框架层和sqlcipher源码优化,使其更高效的表现。
-
多线程高并发:WCDB支持多线程读与读、读与写并发执行,写与写串行执行。
-
批量写操作性能测试:
更多关于WCDB的性能数据,请参考benchmark。
-
-
完整,WCDB覆盖了数据库相关各种场景的所需功能。
- 加密:WCDB提供基于SQLCipher的数据库加密。
- 损坏修复:WCDB内建了Repair Kit用于修复损坏的数据库。
- 反注入:WCDB内建了对SQL注入的保护。
基本要求
- WCDB支持iOS 7、macOS 10.9以上。
- WCDB需使用Xcode 8.0以上版本进行编译。
- 需使用Objective-C++。
通过CocoaPods安装,此处不介绍安装过程,感兴趣可以参考文章:http://www.cnblogs.com/HJiang/p/7228166.html
/*
将一个已有的ObjC类进行ORM绑定的过程如下:
定义该类遵循WCTTableCoding协议。可以在类声明上定义,也可以通过文件模版在category内定义。
使用WCDB_PROPERTY宏在头文件声明需要绑定到数据库表的字段。
使用WCDB_IMPLEMENTATIO宏在类文件定义绑定到数据库表的类。
使用WCDB_SYNTHESIZE宏在类文件定义需要绑定到数据库表的字段。
*/
以例子参考:
.实体类.
新建Message类
Message.h
#import <Foundation/Foundation.h> @interface Message : NSObject /** * 本地id */ @property (nonatomic,assign) int localID; /** * 消息内容 */ @property (nonatomic, strong) NSString *content; /** * 创建时间 */ @property (nonatomic, strong) NSDate *createTime; /** * 最后更新时间 */ @property (nonatomic, strong) NSDate *modifiedTime; /** * 未读消息 */ @property (nonatomic,assign) int unused; @end
Message.mm
#import "Message.h" #import "Message+WCTTableCoding.h" @implementation Message // 利用这个宏定义绑定到表的类 WCDB_IMPLEMENTATION(Message) // 下面四个宏定义绑定到表中的字段 WCDB_SYNTHESIZE(Message, localID) WCDB_SYNTHESIZE(Message, content) WCDB_SYNTHESIZE(Message, createTime) WCDB_SYNTHESIZE(Message, modifiedTime) // 约束宏定义数据库的主键 WCDB_PRIMARY(Message, localID) // 定义数据库的索引属性,它直接定义createTime字段为索引 // 同时 WCDB 会将表名 + "_index" 作为该索引的名称 WCDB_INDEX(Message, "_index", createTime) - (NSString *)description{ return [NSString stringWithFormat:@"localID:%d content:%@ createTime:%@ modifiedTime:%@",_localID,_content,_createTime,_modifiedTime]; } @end
Message+WCTTableCoding.h Message分类
#import "Message.h" #import <WCDB/WCDB.h> @interface Message (WCTTableCoding) <WCTTableCoding> /* 需要绑定到表中的字段在这里声明,在.mm中去绑定 使用WCDB_PROPERTY宏在头文件声明需要绑定到数据库表的字段。 */ WCDB_PROPERTY(localID) WCDB_PROPERTY(content) WCDB_PROPERTY(createTime) WCDB_PROPERTY(modifiedTime) @end
由于WCDB是基于Objective-C++,因此需要将引用WCDB的源文件后缀.m
改为.mm
所以Message.m需修改为.mm
数据库管理类
WCTDatabaseManager.h WCTDatabaseManager.mm
#import <Foundation/Foundation.h> @class WCTDatabase; @interface WCTDatabaseManager : NSObject + (instancetype)shareInstance; - (WCTDatabase *)getDatabase; /** 创建数据库 @param tableName 表名称 @return 是否创建成功 */ - (BOOL)creatDataBaseWithName:(NSString *)tableName; @end
#import "WCTDatabaseManager.h" #import "WCTDatabaseManager+DataBase.h" #import "Message.h" //#import "Message+WCTTableCoding.h" @interface WCTDatabaseManager() { WCTDatabase *database; } @end @implementation WCTDatabaseManager + (instancetype)shareInstance{ static WCTDatabaseManager * instance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[WCTDatabaseManager alloc]init]; }); return instance; } - (NSString *)getDatabasePath{ //获取沙盒根目录 NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; // 文件路径 NSString *filePath = [documentsPath stringByAppendingPathComponent:@"Wechat.sqlite"]; return filePath; } - (WCTDatabase *)getDatabase{ if(!database){ NSString *filePath = [self getDatabasePath]; NSLog(@"wChatDatapath = %@",filePath); database = [[WCTDatabase alloc] initWithPath:filePath]; } return database; } -(BOOL)creatDataBaseWithName:(NSString *)tableName{ [self getDatabase]; // 数据库加密 //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; } @end
WCTDatabaseManager+DataBase.h WCTDatabaseManager分类,引入WCDB头文件
#import <WCDB/WCDB.h> @interface WCTDatabaseManager (DataBase) @end
数据库操作类
#import <Foundation/Foundation.h> @class Message; @interface MessageDao : NSObject - (BOOL)insertMessage:(Message *)message; - (BOOL)insertMessageWithTransaction:(Message *)message; - (BOOL)insertMessageWithBlock:(Message *)message; - (BOOL)deleteMessage:(Message *)message; - (BOOL)updataMessage:(Message *)message; - (NSArray *)seleteMessages; @end
#import "MessageDao.h" #import "WCTDatabaseManager.h" #import <WCDB/WCDB.h> #import "Message.h" #import "Message+WCTTableCoding.h" #define kDataBase [[WCTDatabaseManager shareInstance] getDatabase] @implementation MessageDao - (BOOL)insertMessage:(Message *)message{ return [kDataBase insertObject:message into:@"message"]; } // WCTDatabase 事务操作,利用WCTTransaction - (BOOL)insertMessageWithTransaction:(Message *)message{ BOOL ret = [kDataBase beginTransaction]; ret = [self insertMessage:message]; if (ret) { [kDataBase commitTransaction]; }else{ [kDataBase rollbackTransaction]; } return ret; } // 另一种事务处理方法Block - (BOOL)insertMessageWithBlock:(Message *)message{ BOOL commit = [kDataBase runTransaction:^BOOL{ BOOL ret = [self insertMessage:message]; if (ret) { return YES; }else{ return NO; } } event:^(WCTTransactionEvent event) { NSLog(@"Event %d", event); }]; return commit; } - (BOOL)deleteMessage:(Message *)message{ // 删除 //DELETE FROM message WHERE localID>0; return [kDataBase deleteObjectsFromTable:@"message" where:Message.localID > 0]; } - (BOOL)updataMessage:(Message *)message{ //修改 //UPDATE message SET content="Hello, Wechat!"; return [kDataBase updateAllRowsInTable:@"message" onProperty:Message.content withObject:message]; } - (NSArray *)seleteMessage{ //SELECT * FROM message ORDER BY localID NSArray<Message *> * message = [kDataBase getObjectsOfClass:Message.class fromTable:@"message" orderBy:Message.localID.order()]; return message; } @end
测试方法
#import "ViewController.h" #import "WCTDatabaseManager.h" #import "MessageDao.h" #import "Message.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (IBAction)createDataBaseDidClick:(UIButton *)sender { BOOL result = [[WCTDatabaseManager shareInstance] creatDataBaseWithName:@"message"]; NSLog(@"%@",((result == YES)?@"创建数据库成功":@"创建数据库失败")); } - (IBAction)insertBtnDidClick:(UIButton *)sender { MessageDao *messageDao = [[MessageDao alloc] init]; Message *message = [[Message alloc] init]; message.localID = 1; message.content = @"Hello, WCDB!"; message.createTime = [NSDate date]; message.modifiedTime = [NSDate date]; [messageDao insertMessageWithTransaction:message]; } - (IBAction)updateBtnDidClick:(UIButton *)sender { MessageDao *messageDao = [[MessageDao alloc] init]; Message *message = [[Message alloc] init]; message.content = @"Hello, Wechat!"; [messageDao updataMessage:message]; } - (IBAction)selectBtnDidClick:(UIButton *)sender { MessageDao *messageDao = [[MessageDao alloc] init]; NSArray *messages = [messageDao seleteMessage]; NSLog(@"%@",messages); } - (IBAction)deleteBtnDidClick:(UIButton *)sender { MessageDao *messageDao = [[MessageDao alloc] init]; [messageDao deleteMessage:nil]; } @end
更多的查询操作后续更新.