到年底了该溯,公司基本上沒(méi)什么事情了岛抄。這一段時(shí)間研究了下FMDB,公司項(xiàng)目用的是coredata狈茉。查了一下資料對(duì)比了一下realm夫椭,F(xiàn)MDB,coredata氯庆。
realm是性能最高的蹭秋。但是realm國(guó)內(nèi)資料基本不多,而且大部分都是官網(wǎng)公布的例子堤撵。而且cocoapods基本拉不下來(lái)仁讨。但是也花了2天時(shí)間使用了一下realm,給我的感覺(jué)就是難用实昨。而且對(duì)于整個(gè)工程來(lái)說(shuō)會(huì)復(fù)雜很多洞豁,因?yàn)閞ealm模型是必須繼承RealmObject的。這樣就必須多出一套模型屠橄。
FMDB基于sqlite用OC封裝的一個(gè)庫(kù)族跛。FMDB最好是用一個(gè)單例封裝起來(lái),方便項(xiàng)目的使用锐墙。提供一個(gè)Demo礁哄,有需要的同學(xué)可以去看看。
先說(shuō)單線程操作數(shù)據(jù)庫(kù):
創(chuàng)建一個(gè)叫FMDBManage的單例類(lèi)溪北,然后倒入相關(guān)的頭文件桐绒,創(chuàng)建對(duì)象。
創(chuàng)建數(shù)據(jù)庫(kù):
- (void)createFMDB
{
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [documentsPath stringByAppendingPathComponent:@"test.sqlite"];
NSLog(@"數(shù)據(jù)庫(kù)地址:%@",filePath);
self.db = [FMDatabase databaseWithPath:filePath];
self.queue = [FMDatabaseQueue databaseQueueWithPath:filePath];
}
創(chuàng)建表:
- (void)createTable
{
if ([self.db open]) {
NSString *userSql = @"CREATE TABLE IF NOT EXISTS 'user' (user_phone test primary key,user_id test,user_sex test,time test)";
NSString *travelSql = @"CREATE TABLE IF NOT EXISTS 'travel' (travel_id test primary key,own_id test,title test,date test)";
if (![self.db executeUpdate:userSql]) {
NSLog(@"創(chuàng)建表失敗");
}
if (![self.db executeUpdate:travelSql]) {
NSLog(@"創(chuàng)建表失敗");
}
[self.db close];
}
}
操作數(shù)據(jù)庫(kù)的時(shí)候必須要先open然后使用完了在close之拨。創(chuàng)建表的時(shí)候注意設(shè)置約束茉继。
保存數(shù)據(jù):
- (void)saveUser:(User *)user
{
if ([self.db open]) {
BOOL insert = [self.db executeUpdate:@"INSERT INTO user(user_phone,user_id,user_sex,time)VALUES(?,?,?,?)",user.phone,user.ID,user.sex,[self currentTime]];
if (!insert) {
//執(zhí)行更新操作
NSLog(@"執(zhí)行更新操作");
[self updateUser:user];
}
[self.db close];
}
}
因?yàn)橐呀?jīng)設(shè)置好了主鍵,所以不管是新用戶(hù)數(shù)據(jù)還是更新數(shù)據(jù)蚀乔。我們都只需要在插入失敗時(shí)自動(dòng)去調(diào)用更新數(shù)據(jù)API烁竭。
更新數(shù)據(jù):
- (void)updateUser:(User *)user
{
if ([self.db open]) {
[self.db executeUpdate:@"UPDATE 'user' SET user_id = ?, user_sex = ?,time = ? WHERE user_phone = ? ",user.ID,user.sex,[self currentTime],user.phone];
[self.db close];
}
}
查詢(xún)數(shù)據(jù):
//查詢(xún)所有user數(shù)據(jù),按照某一個(gè)字段降序排列(默認(rèn)是升序小到大)
- (NSMutableArray *)getAllUserOrderByTime
{
NSMutableArray *userArr = [[NSMutableArray alloc]init];
if ([self.db open]) {
FMResultSet *result = [self.db executeQuery:@"select * from user order by time desc"];
while ([result next]) {
User *user = [[User alloc]init];
user.ID = [result stringForColumn:@"user_id"];
user.phone = [result stringForColumn:@"user_phone"];
user.sex = [result stringForColumn:@"user_sex"];
user.lastLogintime = [result stringForColumn:@"time"];
[userArr addObject:user];
}
[self.db close];
}
return userArr;
}
刪除數(shù)據(jù):
- (void)deleteUserWithPhone:(NSString *)phone
{
if ([self.db open]) {
[_db executeUpdate:@"DELETE FROM user WHERE user_phone = ?",phone];
[self.db close];
}
}
下面在說(shuō)下怎么關(guān)聯(lián)表吉挣。比如你的app用戶(hù)登錄了派撕,然后在這個(gè)用戶(hù)下產(chǎn)生的數(shù)據(jù)肯定就只是這個(gè)用戶(hù)的數(shù)據(jù),其他用戶(hù)是不能訪問(wèn)的睬魂。
創(chuàng)建兩個(gè)數(shù)據(jù)Model终吼。
怎么去關(guān)聯(lián)表呢?在創(chuàng)建表的代碼中有一個(gè)own_id字段氯哮,這個(gè)字段用用戶(hù)的唯一標(biāo)識(shí)去設(shè)置际跪。取得時(shí)候也通過(guò)用戶(hù)唯一標(biāo)識(shí)就OK了。
給當(dāng)前用戶(hù)添加Travel模型:
//給當(dāng)前登錄用戶(hù)添加行程
- (void)saveTravel:(Travel *)travel toUser:(NSString *)phone
{
if ([self.db open]) {
[self.db executeUpdate:@"INSERT INTO travel(travel_id,own_id,title,date)VALUES(?,?,?,?)",travel.travel_id,phone,travel.title,[self baseDecodeWithDic:travel.totalDic]];
[self.db close];
}
}
//查詢(xún)當(dāng)前登錄用戶(hù)的行程
- (void)getTravelAt:(NSString *)travelID fromUser:(NSString *)phone
{
if ([self.db open]) {
FMResultSet *result = [self.db executeQuery:@"select * from travel where own_id = ?",phone];
while ([result next]) {
Travel *travel = [[Travel alloc]init];
travel.travel_id = [result stringForColumn:@"travel_id"];
travel.own_id = [result stringForColumn:@"own_id"];
travel.title = [result stringForColumn:@"title"];
NSString *strData = [result stringForColumn:@"date"];
travel.totalDic = [self baseEncodeWithString:strData];
NSLog(@"travel:%@",travel);
}
[self.db close];
}
}
//刪除某一個(gè)用戶(hù)的所有行程
- (void)deleteAllTravelFromUser:(NSString *)phone
{
if ([self.db open]) {
[self.db executeUpdate:@"DELETE FROM travel WHERE own_id = ?",phone];
[self.db close];
}
}
如果app需要自動(dòng)登錄功能,那怎么去確定那個(gè)用戶(hù)是最后一個(gè)登錄的姆打。我這里使用到一個(gè)時(shí)間戳良姆,通過(guò)對(duì)時(shí)間排序去判斷用戶(hù)登錄的先后。
- (NSString *)currentTime
{
NSDateFormatter *formatter =[[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyyMMddHHmmss"];
NSString *currentTime = [formatter stringFromDate:[NSDate date]];
return currentTime;
}
如果app需要存儲(chǔ)字典或數(shù)組的話(huà)穴肘,就需要對(duì)字典或數(shù)組進(jìn)行編碼:
//字典編碼
- (NSString *)baseDecodeWithDic:(NSMutableArray *)dic{
NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:0 error:nil];
NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
return str;
}
//字符串解碼
- (NSMutableArray *)baseEncodeWithString:(NSString *)str
{
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
NSMutableArray *dic = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
return dic;
}
這些都是在同一個(gè)線程下操作數(shù)據(jù)庫(kù)歇盼。但是當(dāng)多線程去操作數(shù)據(jù)庫(kù)的話(huà)舔痕,數(shù)據(jù)就會(huì)混亂评抚。下面說(shuō)下線程安全:
//插入數(shù)據(jù),如果表中已有則執(zhí)行更新操作(線程安全)
- (void)saveUserWithQueue:(User *)user
{
dispatch_queue_t q1 = dispatch_queue_create("saveUser", NULL);
dispatch_async(q1, ^{
[self.queue inDatabase:^(FMDatabase *db) {
[self.db open];
BOOL insert = [self.db executeUpdate:@"INSERT INTO user(user_phone,user_id,user_sex)VALUES(?,?,?)",user.phone,user.ID,user.sex];
if (!insert) {
//執(zhí)行更新操作
NSLog(@"執(zhí)行更新操作");
}
[self.db close];
}];
});
}
//更新數(shù)據(jù)伯复,(線程安全)
- (void)updateUserWithQueue:(User *)user
{
dispatch_queue_t q1 = dispatch_queue_create("updateUser", NULL);
dispatch_async(q1, ^{
[self.queue inDatabase:^(FMDatabase *db) {
[self.db open];
[self.db executeUpdate:@"UPDATE 'user' SET user_id = ? WHERE user_phone = ? ",user.ID,user.phone];
[self.db executeUpdate:@"UPDATE 'user' SET user_sex = ? WHERE user_phone = ? ",user.sex,user.phone];
[self.db close];
}];
});
}
就簡(jiǎn)單的舉著兩個(gè)例子慨代。