介紹
realm是一個跨平臺移動數據庫引擎,支持iOS、OS X(Objective-C和Swift)以及Android。
2014年7月發布。由YCombinator孵化的創業團隊歷時幾年打造,是第一個專門針對移動平臺設計的數據庫。目標是取代SQLite。
為了徹底解決性能問題,核心數據引擎C++打造,并不是建立在SQLite之上的ORM。如果對數據引擎實現想深入了解可以查看:Realm 核心數據庫引擎探秘。因此得到的收益就是比普通的ORM要快很多,甚至比單獨無封裝的SQLite還要快。
因為是ORM,本身在設計時也針對移動設備(iOS、Android),所以非常簡單易用,學習成本很低。
吸引我的地方
- 首先是realm的速度,雖然一般的手機客戶端不會用到大數據的情況,但有些情況你還是會經常遇到的。比如要存全國的省市區,這個數據量就很大,而且還是關系型的。如果用coredata會灰常的慢,這個時候Realm就派上用場了。
- 其次是realm的使用,realm相對于coredata,不管是增刪改查,還是數據庫版本的更新,都要更加的簡單,比較適合新手使用,降低了團隊學習的成本。
這里要說一下數據庫的版本更新,當我們的數據庫中表的字段發生變化時,為了兼容老版本,需要對數據庫進行升級。這個在coredata里是有的,但是需要操作的地方很多,既要在試圖里修改,還要重新生產實例。但是realm就比較方便了,幾行代碼。而且如果改動特別大,可以直接創建新的庫出來,比coredata要靈活。 - 最后realm發展到現在也相對比較成熟了,有團隊專門去維護,熱度也比較高,可以在一些功能上試用起來。
簡單的展示一下速度對比:
每秒能在20萬條數據中進行查詢后count的次數。realm每秒可以進行30.9次查詢后count。查詢速度要比coredata快30倍,非常恐怖。
部署realm
說了這么多好處,現在開始實施。首先我們要部署realm數據庫,官網上介紹了四種部署方式:
1.加入動態庫2.通過cocoapods3.通過carthage4.加靜態庫
這里我用的是cocoapods,直接在podfile中加一句話:
pod 'Realm'
然后pod update ,庫比較大,時間會有點長。
realm基本操作
數據庫操作大概就是增刪改查,接下來我會以這個分為四大塊來逐一介紹
創建model
#import "CityEntity.h"
#import <Realm/Realm.h>
RLM_ARRAY_TYPE(CityEntity)
@interface ProvinceEntity : RLMObject
@property NSString *enName;
@property int pid;
@property NSString *prefixLetter;
@property NSString *shortName;
@property int sId;
@property int type;
@property RLMArray<CityEntity *><CityEntity> *citys;
@end
這樣就創建好了一個數據模型,可以對比一下coredata的數據模型,明顯簡潔了:
- 不要去聲明屬性的類型,原子性,強弱類型都不需要指定
- 支持int類型,coredata中的int 只能轉為nsnumber
這里要注意的是,如果需要設置一對多的關系,需要兩個步驟:
- 1.首先申明RLM_ARRAY_TYPE(CityEntity),這句話的作用是申明一個RLMArray<CityEntity> type。這個申明可以放在兩個地方,一個是你需要關聯的那個類的最上方,就像我現在寫的這樣,放在ProvinceEntity上方。你也可以放在CityEntity的最后,也就是@end下方。如同這樣:
#import "AreaEntity.h"
#import <Realm/Realm.h>
RLM_ARRAY_TYPE(AreaEntity)
@interface CityEntity : RLMObject
@property NSString *enName;
@property int pid;
@property NSString *prefixLetter;
@property NSString *shortName;
@property int sId;
@property int type;
@property RLMArray<AreaEntity *><AreaEntity> *areas;
//@property ProvinceEntity *inProvince;
@end
RLM_ARRAY_TYPE(CityEntity)
- 2.然后增加關聯的屬性@property RLMArray<CityEntity *><CityEntity> *citys;
RLMArray<CityEntity *><CityEntity> * citys 這樣申明看著有點怪怪的,拆為三部分來看
RLMArray,這個沒什么好說,就是數組類型
<CityEntity *>官方解釋屬性的特別化(generic specialization),這可以阻止在編譯時使用錯誤對象類型的數組。
<CityEntity>這個其實和RLMArray是連在一起的, 此RLMArray遵守的協議,可以讓 Realm 知曉如何在運行時確定數據模型的架構。
新增數據
首先要造好數據(展示關鍵代碼):
ProvinceEntity* province=[[ProvinceEntity alloc] init];
//...賦值
CityEntity *city = [[CityEntity alloc] init];
[province.citys addObject:city];
其實有三種創建方式:
// (1) Create a Dog object and then set its properties
Dog *myDog = [[Dog alloc] init];myDog.name = @"Rex";myDog.age = 10;
// (2) Create a Dog object from a dictionary
Dog *myOtherDog = [[Dog alloc] initWithValue:@{@"name" : @"Pluto", @"age" : @3}];
// (3) Create a Dog object from an array
Dog *myThirdDog = [[Dog alloc] initWithValue:@[@"Pluto", @3]];
然后把記錄插入到數據庫中:
// Get the default Realm
RLMRealm *realm = [RLMRealm defaultRealm];
// You only need to do this once (per thread)
// Add to Realm with transaction
[realm beginWriteTransaction];
[realm addObject:province];
[realm commitWriteTransaction];
查詢數據
如果用過coredata,那你一定對NSPredicate會很熟悉。Realm即支持NSPredicate也支持斷言字符串查詢,這樣從coredata遷移過來的話,之前的查詢語句就不用修改,直接沿用即可:
// 使用斷言字符串查詢
RLMResults<ProvinceEntity *> *provinceArray = [ProvinceEntity objectsWhere:@"shortName = '江蘇'"];
// 使用 NSPredicate 查詢
NSPredicate *pred = [NSPredicate predicateWithFormat:@"shortName = '江蘇'"];
provinceArray = [ProvinceEntity objectsWithPredicate:pred];
如果有多條件的話,可以用and,也可以分布查詢,從查詢結果中再做查詢,支持鏈式查詢:
RLMResults<Dog *> *tanDogs = [Dog objectsWhere:@"color = '棕黃色'"];RLMResults<Dog *> *tanDogsWithBNames = [tanDogs objectsWhere:@"name BEGINSWITH '大'"];
RLMResults允許您指定一個排序標準,從而可以根據一個或多個屬性進行排序。比如說,下列代碼將上面例子中返回的狗狗根據名字升序進行排序:
// 排序名字以“大”開頭的棕黃色狗狗
RLMResults<Dog *> *sortedDogs = [[Dog objectsWhere:@"color = '棕黃色' AND name BEGINSWITH '大'"] sortedResultsUsingProperty:@"name" ascending:YES];
更新數據
這里要吐槽一下coredata的更新,coredata沒有更新,要想完成更新的操作只能先查再刪,灰常麻煩,效率也低。realm就要好很多,他支持更新。
- 你可以找到具體的一條數據然后去更新:
RLMResults<ProvinceEntity *>* provinceArray=[ProvinceEntity allObjects];
[[RLMRealm defaultRealm] transactionWithBlock:^{
ProvinceEntity *province=[provinceArray firstObject];
province.shortName=@"浙江";
}];
- 你也可以設置一個主鍵,根據主鍵去更新,更新需要擁有一個主鍵---Primary Keys:
@implementation Person
+ (NSString *)primaryKey {
return @"id";
}
@end
然后通過realm提供的接口:
// Creating a book with the same primary key as a previously saved
bookBook *cheeseBook = [[Book alloc] init];
cheeseBook.title = @"Cheese recipes";
cheeseBook.price = @9000;
cheeseBook.id = @1;
// Updating book with id = 1
[realm beginWriteTransaction];
[realm addOrUpdateObject:cheeseBook];
[realm commitWriteTransaction];
刪除數據
刪除數據分為三種:
- 單條記錄刪除:
// Delete an object with a transaction
[realm beginWriteTransaction];
[realm deleteObject:cheeseBook];
[realm commitWriteTransaction];
- 多條記錄刪除:
// Delete an object with a transaction
[[RLMRealm defaultRealm] transactionWithBlock:^{
[[RLMRealm defaultRealm] deleteObjects:result];
}];
- 全部刪除:
// Delete an object with a transaction
[[RLMRealm defaultRealm] transactionWithBlock:^{
[[RLMRealm defaultRealm] deleteAllObjects];
}];
總結
realm作為一款跨平臺的數據庫,首先兼容性就比較好。就ios而言,oc和swift都支持。性能又非常的強勁,速度很快。上面介紹了realm的基本操作,可以看到realm使用起來是非常簡單的,而且他已經幫你把事務做好了。這就保證了realm在實際使用中的安全性,不會因為一些突發情況造成數據的紊亂。之后我會對他進行更深入的探討,如果你感興趣可以關注我。
參考:
感謝下面文章的作者:
http://www.cocoachina.com/ios/20160513/16241.html
感謝官網:
https://realm.io/