基于sqlite的key-value存儲工具:YTKKeyValueStore

jopen 10年前發布 | 42K 次閱讀 NoSQL數據庫 YTKKeyValueStore

前言

還記得大學剛學數據庫那會兒,天真地以為世界上所有的存儲都需要用數據庫來做。后來畢業后,正值NOSQL流行,那時我在網易參與了網易微博的開發,我們當時使用了有道自己做的“BigTable”— OMAP來存儲微博數據,那個時候才發現,其實Key-Value這種簡單的存儲也能搞定微博這類不太簡單的存儲邏輯。

相比MYSQL,當數據量上千萬后,NOSQL的優勢體現出來了:對于海量數據,NOSQL在存取速度上沒有任何影響,另外,天生的多備份和分布式,也說數據安全和擴容變得異常容易。

iOS端的嘗試

后來我從后臺轉做iOS端的開發,我就嘗試了在iOS端直接使用Key-Value式的存儲。經過在粉筆網、猿題庫、小猿搜題三個客戶端中的嘗試后,我發現Key-Value式的存儲不但完全能夠滿足大多數移動端開發的需求,而且非常適合移動端采用。主要原因是:移動端存儲的數據量不會很大:

  • 如果是單機的應用(例如效率工具Clear),用戶自己一個人創建的數據最多也就上萬條。
  • 如果是有服務端的應用(例如網易新聞,微博),那移動端通常不會保存全量的數據,每次會從服務器上獲取數據,本地只是做一些內容的緩存而已,所以也不會有很大的數據量。

如果數據量不大的話,那么在iOS端使用最簡單直接的Key-Value存儲就能帶來開發上的效率優勢。它能保證:

  1. Model層的代碼編寫簡單,易于測試。
  2. 由于Value是JSON格式,所以在做Model字段更改時,易于擴展和兼容。

實現方案

在存儲引擎上,2年前我直接選擇了Sqlite當做存儲引擎,相當于每個數據庫表只有Key,Value兩個字段。后來,隨著LevelDB的流行,業界也有一些應用采用了LevelDB來做iOS端的Key-Value存儲引擎,例如開源的ViewFinder

因為LevelDB本身并不是為移動端設計的,我擔心它過于占用內存,我自己也沒有看到業界有在移動端針對LevelDB做很詳細的測試,連 LevelDB的iOS端移植都不是官方做的。加上我自己寫的基于Sqlite的Key-Value存儲用著也沒有什么問題,所以我也就一直沒有更換成 LevelDB。

開源

經過兩年的使用和測試,我認為它非常好用,而且代碼也非常簡單,只有不到400行。所以現在開源分享給大家,這個項目叫YTKKeyValueStore,項目在這里。以下是一個簡單的使用示例:

YTKKeyValueStore *store = [[YTKKeyValueStore alloc] initDBWithName:@"test.db"];
NSString *tableName = @"user_table";
[store createTableWithName:tableName];
// 保存
NSString *key = @"1";
NSDictionary *user = @{@"id": @1, @"name": @"tangqiao", @"age": @30};
[store putObject:user withId:key intoTable:tableName];
// 查詢
NSDictionary *queryUser = [store getObjectById:key fromTable:tableName];
NSLog(@"query data result: %@", queryUser);

集成說明

使用本項目,你需要將開源代碼中的YTKKeyValueStore.hYTKKeyValueStore.m添加到你的工程中,并且在工程設置的Link Binary With Libraries中,增加libsqlite3.dylib,如下圖所示:

基于sqlite的key-value存儲工具:YTKKeyValueStore

由于時間關系,當前還未提供Cocoapods方式集成。

使用說明

所有的接口都封裝在YTKKeyValueStore類中。以下是一些常用方法說明。

打開(或創建)數據庫

通過initDBWithName方法,即可在程序的Document目錄打開指定的數據庫文件。如果該文件不存在,則會創建一個新的數據庫。

// 打開名為test.db的數據庫,如果該文件不存在,則創新一個新的。
YTKKeyValueStore *store = [[YTKKeyValueStore alloc] initDBWithName:@"test.db"];

創建數據庫表

通過createTableWithName方法,我們可以在打開的數據庫中創建表,如果表名已經存在,則會忽略該操作。如下所示:

YTKKeyValueStore *store = [[YTKKeyValueStore alloc] initDBWithName:@"test.db"];
NSString *tableName = @"user_table";
// 創建名為user_table的表,如果已存在,則忽略該操作
[store createTableWithName:tableName];

讀寫數據

YTKKeyValueStore類提供key-value的存儲接口,存入的所有數據需要提供key以及其對應的value,讀取的時候需要提供key來獲得相應的value。

YTKKeyValueStore類支持的value類型包括:NSString, NSNumber, NSDictionary和NSArray,為此提供了以下接口:

- (void)putString:(NSString *)string withId:(NSString *)stringId intoTable:(NSString *)tableName;
- (void)putNumber:(NSNumber *)number withId:(NSString *)numberId intoTable:(NSString *)tableName;
- (void)putObject:(id)object withId:(NSString *)objectId intoTable:(NSString *)tableName;

與此對應,有以下value為NSString, NSNumber, NSDictionary和NSArray的讀取接口:

- (NSString *)getStringById:(NSString *)stringId fromTable:(NSString *)tableName;
- (NSNumber *)getNumberById:(NSString *)numberId fromTable:(NSString *)tableName;
- (id)getObjectById:(NSString *)objectId fromTable:(NSString *)tableName;

刪除數據接口

YTKKeyValueStore提供了以下接口用于刪除數據。

// 清除數據表中所有數據
- (void)clearTable:(NSString *)tableName;

// 刪除指定key的數據
- (void)deleteObjectById:(NSString *)objectId fromTable:(NSString *)tableName;

// 批量刪除一組key數組的數據
- (void)deleteObjectsByIdArray:(NSArray *)objectIdArray fromTable:(NSString *)tableName;

// 批量刪除所有帶指定前綴的數據
- (void)deleteObjectsByIdPrefix:(NSString *)objectIdPrefix fromTable:(NSString *)tableName;

更多接口

YTKKeyValueStore還提供了以下接口來獲取表示內部存儲的key-value對象。

// 獲得指定key的數據
- (YTKKeyValueItem *)getYTKKeyValueItemById:(NSString *)objectId fromTable:(NSString *)tableName;
// 獲得所有數據
- (NSArray *)getAllItemsFromTable:(NSString *)tableName;

由于YTKKeyValueItem類帶有createdTime字段,可以獲得該條數據的插入(或更新)時間,以便上層做復雜的處理(例如用來做緩存過期邏輯)。

其它

兩年前寫過不少測試用例,后來給弄丟了,所以現在開項項目中還沒有測試用例。由于時間關系,更詳細的使用說明稍后會更新到項目中。

項目主頁:http://www.baiduhome.net/lib/view/home/1414821035872

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!