微信數據存儲WCDB for iOS/macOS

 

WCDB

WCDB是一個高效、完整、易用的移動數據庫框架,基於SQLCipher,支持iOS, macOS。html

 

WCDB for iOS/macOS

基本特性

  • 易用,WCDB支持一句代碼便可將數據取出並組合爲object。git

    • WINQ(WCDB語言集成查詢):經過WINQ,開發者無須爲了拼接SQL的字符串而寫一大坨膠水代碼。github

    • ORM(Object Relational Mapping):WCDB支持靈活、易用的ORM。開發者能夠很便捷地定義表、索引、約束,並進行增刪改查操做。sql

      [database getObjectsOfClass:WCTSampleConvenient.class
                        fromTable:tableName where:WCTSampleConvenient.intValue>=10 limit:20];
  • 高效,WCDB經過框架層和sqlcipher源碼優化,使其更高效的表現。數據庫

    • 多線程高併發:WCDB支持多線程讀與讀、讀與寫併發執行,寫與寫串行執行。多線程

    • 批量寫操做性能測試:併發

      更多關於WCDB的性能數據,請參考benchmarkapp

  • 完整,WCDB覆蓋了數據庫相關各類場景的所需功能。框架

    • 加密:WCDB提供基於SQLCipher的數據庫加密。
    • 損壞修復:WCDB內建了Repair Kit用於修復損壞的數據庫。
    • 反注入:WCDB內建了對SQL注入的保護。

基本要求

  • WCDB支持iOS 七、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 七、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

 

更多的查詢操做後續更新.

相關文章
相關標籤/搜索