工作二总结——objective-C中sqlite3数据库的处理(其二)
2014-11-02 18:40
197 查看
这篇是其一中工作的最终实现,使用了FMDB,更具有objective-C的风格。
[db open]进行的操作是打开数据库,并返回BOOL值表示是否打开成功。如果没有数据库,会自行创建。
依然如同(其一),先删去数据库相应的表再添加新表:
两者的区别是对格式占位符不同,WithFormat会用%@、%s之类的占位符,而前者全部占位符都是?。
本文还是那三个表,entity表和tag表的name字段必须唯一。entity非常好说,一行就一个,不会有重复的情况,而tag呢?
上一篇中完全没有进行判断,直接依靠数据库的unique字段来搞定。
然而实际工作中出现的情况是,往往有上万个entity,而tag只有十几个。为了这十几个不断重复的tag我们要进行entity数量*4次数据库插入,要知道数据库的数据交换比内存中直接交换要慢的多,这十万次数据库处理的时间开销实在不忍直视。
因此我用内存中处理的方式判断tag是否重复,也就是一个NSMutableDictionary。
如果不是这样,那么肯定可以得到tag的id,(其一)使用select语句来查找tag的id,而在这里,NSMutableDictionary就能解决这个问题,又减少了一次数据库查询开销,真是一举两得!
dictionary的实质是个hash table,其查询效率还是很高的。
插入数据的话,使用
直接贴全文好了,我注释做的很认真,应该可以看懂。
本文没有用到select语句,其实FMDBselect语句极其简单,它会将查询结果储存在一个resultSet里面,之后根据resultSet的方法获取需要的数据即可。
我会在(其三)中讲解select语句用法。
下篇文章就不是这个电脑上的工作了,下个工作是把生成的数据库的这三个表加载到iPhone上,制成iphone上的4个NSDictionary。
第一个是tag对应其映射的entity列表
第二个是entity对应其映射的tag列表
第三个是tag对应其分数
第四个是entity对应其分数
根据最初乱码文本得到的这4个NSDictionary在之后的工作中会有很大作用。
FMDatabase *db = [[FMDatabase alloc] initWithPath:[NSString stringWithFormat:@"%s", databasePath]]; if ([db open] == NO) { NSLog(@"Failed to open database!"); return 1; }首先打开路径下的数据库,顺便有个小技巧,如何把C的字符串转换为NSString?我就是用stringWithFormat:@"%s"的方式。
[db open]进行的操作是打开数据库,并返回BOOL值表示是否打开成功。如果没有数据库,会自行创建。
依然如同(其一),先删去数据库相应的表再添加新表:
// 为了防止表格式有问题,因此先删去同名表,再创建相应表 [db executeUpdateWithFormat:@"drop table entity;"]; BOOL ret = [db executeUpdateWithFormat:@"create table entity(id integer not null, name TEXT not null unique, score integer, popularity integer);"]; if (ret != YES) { NSLog(@"Creating table entity failed!"); exit(1); }数据库对象的实例方法executeUpdate和executeUpdateWithFormat用于更改数据库内容。DROP、CREATE、INSERT、DELETE都在其列。
两者的区别是对格式占位符不同,WithFormat会用%@、%s之类的占位符,而前者全部占位符都是?。
本文还是那三个表,entity表和tag表的name字段必须唯一。entity非常好说,一行就一个,不会有重复的情况,而tag呢?
上一篇中完全没有进行判断,直接依靠数据库的unique字段来搞定。
然而实际工作中出现的情况是,往往有上万个entity,而tag只有十几个。为了这十几个不断重复的tag我们要进行entity数量*4次数据库插入,要知道数据库的数据交换比内存中直接交换要慢的多,这十万次数据库处理的时间开销实在不忍直视。
因此我用内存中处理的方式判断tag是否重复,也就是一个NSMutableDictionary。
NSMutableDictionary *allTags = [NSMutableDictionary dictionary];/key当然是tag名称,而value则是tag的id,如此,如果出现
allTags[tagObject] == nil;的情况,就可以判断没有这个tag,可以加入到数据库中。
如果不是这样,那么肯定可以得到tag的id,(其一)使用select语句来查找tag的id,而在这里,NSMutableDictionary就能解决这个问题,又减少了一次数据库查询开销,真是一举两得!
dictionary的实质是个hash table,其查询效率还是很高的。
插入数据的话,使用
NSString *SQL = [NSString stringWithFormat:@"insert into entity(id,name,score,popularity) values(%d,'%s',%s, %d);", entityCount, entityName, entityScore, 0]; ret = [db executeUpdate:SQL];我不知道为什么,直接用FMDB的Format老出现问题,因此我直接调整好格式输入就行。
直接贴全文好了,我注释做的很认真,应该可以看懂。
本文没有用到select语句,其实FMDBselect语句极其简单,它会将查询结果储存在一个resultSet里面,之后根据resultSet的方法获取需要的数据即可。
我会在(其三)中讲解select语句用法。
下篇文章就不是这个电脑上的工作了,下个工作是把生成的数据库的这三个表加载到iPhone上,制成iphone上的4个NSDictionary。
第一个是tag对应其映射的entity列表
第二个是entity对应其映射的tag列表
第三个是tag对应其分数
第四个是entity对应其分数
根据最初乱码文本得到的这4个NSDictionary在之后的工作中会有很大作用。
#import <Foundation/Foundation.h> #import "FMDB.h" const char *databasePath; const char *txtPath; int entityCount, tagCount, mapCount; int main(int argc, const char * argv[]) { if (argc != 3) { NSLog(@"Wrong arg number! Please type in txt path at first, and then the db path!"); return 1; } txtPath = argv[1]; FILE *txtFile = fopen(txtPath, "r"); if (!txtFile) { NSLog(@"File loading is failed!"); return 1; } databasePath = argv[2]; FMDatabase *db = [[FMDatabase alloc] initWithPath:[NSString stringWithFormat:@"%s", databasePath]]; if ([db open] == NO) { NSLog(@"Failed to open database!"); return 1; } // 为了防止表格式有问题,因此先删去同名表,再创建相应表 [db executeUpdateWithFormat:@"drop table entity;"]; BOOL ret = [db executeUpdateWithFormat:@"create table entity(id integer not null, name TEXT not null unique, score integer, popularity integer);"]; if (ret != YES) { NSLog(@"Creating table entity failed!"); exit(1); } [db executeUpdateWithFormat:@"drop table tag;"]; ret = [db executeUpdateWithFormat:@"create table tag(id integer not null, name TEXT not null unique, score integer, popularity integer);"]; if (ret != YES) { NSLog(@"Creating table tag failed!"); exit(1); } [db executeUpdateWithFormat:@"drop table map;"]; ret = [db executeUpdateWithFormat:@"create table map(id integer not null, entity_id not null, tag_id integer);"]; if (ret != YES) { NSLog(@"Creating table map failed!"); exit(1); } // 用C的方式操作文本文件更加方便 char stringFromTxt[500], last[500]; //开始读取txt中数据,stringFromTxt代表txt一行,last表示上次处理的一行 fgets(stringFromTxt, 500, txtFile); memset(last, 0, sizeof(last)); NSMutableDictionary *allTags = [NSMutableDictionary dictionary];//内存判断tag是否重复比让数据库判断unique值更快 while (1) { // 每趟循环处理文本的一行,循环结束条件为“到达最后一行”,经测试,下面两种情况覆盖了结束条件 if (strcmp(last, stringFromTxt) == 0 || stringFromTxt == NULL){ break; } // 插入entity和score的数据 char *entityName = strtok(stringFromTxt," \t"); char *entityScore = strtok(NULL, " \t"); NSString *SQL = [NSString stringWithFormat:@"insert into entity(id,name,score,popularity) values(%d,'%s',%s, %d);", entityCount, entityName, entityScore, 0]; ret = [db executeUpdate:SQL]; if (ret != YES) NSLog(@"插入entity失败,第%d次", entityCount); // 开始处理tag,txt文件中出现过一个entity对应多个相同tag的情况,在map表构造中应该极力避免这种情况,用mutableSet可以保证高效 NSMutableSet *tagSet = [NSMutableSet set]; char *tag = strtok(NULL, " \n\t"); while (tag != NULL) { // entity对应了两个相同的tag,直接跳过,处理下一个tag NSString *tagObject = [NSString stringWithFormat:@"%s", tag];//会多次使用,因此先存下来 if ([tagSet containsObject:tagObject] == NO) { [tagSet addObject:tagObject]; } else { tag = strtok(NULL, " \t\n"); continue; } // 如果是新出现的tag,就放入tag总集,查询开销为O(log(tag数)) NSNumber *tagId = allTags[tagObject]; if (tagId == nil) { tagId = [NSNumber numberWithInt:tagCount]; [allTags setObject:tagId forKey:tagObject]; // 随机得到tagScore,并插入tag表,只有新出现的tag才有必要加入tag表 int tagScore = arc4random() % 101; SQL = [NSString stringWithFormat:@"insert into tag(id,name,score,popularity) values(%d, '%s', %d, %d);", tagCount ++, tag, tagScore, 0]; ret = [db executeUpdate:SQL]; } // 需要将所有tag映射关系添加至map表 int intTagId = [tagId intValue]; SQL = [NSString stringWithFormat:@"insert into map(id,entity_id,tag_id) values(%d, %d, %d);", mapCount++, entityCount, intTagId]; [db executeUpdate: SQL]; tag = strtok(NULL, " \t\n"); } strcpy(last, stringFromTxt); fgets(stringFromTxt, 500, txtFile); entityCount ++; } [db close]; return 0; }
相关文章推荐
- 工作二总结——objective-C中sqlite3数据库的处理(其三) sqlite3数据库事务的使用
- 工作二总结——objective-C中sqlite3数据库的处理(其一)
- android大型数据库(sqlite)处理及其他问题总结
- 数据库处理应用总结OLAP和OLTP
- 关于数据库一致改关闭下redo日志文件丢失的处理办法的总结
- Orace数据库锁表的处理与总结<摘抄与总结三>
- Orace数据库锁表的处理与总结<摘抄与总结二>
- java中数据库访问方式的不同处理数据总结:
- 解决"System.AccessViolationException”类型的未经处理的异常在 未知模块(IIS Worker Process 已停止工作)导致无法连接远程数据库的问题
- 数据库查询优化方案(处理上百万级记录如何提高处理查询速度)总结不好之处请指点----
- 工作笔记总结——数据库
- 关于数据库一致改关闭下redo日志文件丢失的处理办法的总结
- 工作项目总结(一)之数据库操作
- 工作中itext遇到的一些问题,做一下处理总结(2012.06.19)
- JAVA--数据库事务处理(总结别人的)
- 工作笔记总结——数据库
- c/objective-c/win32/mfc/qt 异常处理与总结
- Objective-C NSString字符串处理简单总结 plus 字符串与数值互相转换
- c/objective-c/win32/mfc/qt 异常处理与总结
- 工作中常见的浏览器兼容处理总结