工作二总结——objective-C中sqlite3数据库的处理(其三) sqlite3数据库事务的使用
来源:互联网 发布:嵌入式软件版本说明 编辑:程序博客网 时间:2024/05/17 19:58
以前知道的太少了,这样大量的数据更新居然没有用到数据库事务,怪不得时间开销这么高。
工作二后来优化了一下,加入了sqlite3的事务,效果十分明显,70秒的数据库生成时间缩短到了1.5秒。
事务(transaction)的原理是,对数据库进行更新的语句先储存起来,储存到一定程度将这些语句一并提交(commit),如果尚未提交,但中途出现了异常,则这些语句都可以撤回(rollback)。
使用事务有两个非常明显的好处:
1、将大量更新语句合并到一起,极大的缩短了访问数据库的次数,如此大量提高了效率和吞吐量。例如本人的“工作二”,将八万多次数据库更新合并到一次提交,原操作时间70秒降低到了1.5秒,效率提高的幅度简直可怕。
2、避免了一些非常恶心的情况,比如同样一个对象有许多不同的属性都要插入到数据库的不同表中,需要多句sql更新才能完成操作。如果操作中途出现了异常,则可能某个对象只有一半的数据输入了数据库,还有另一半是空白的,这还不如完全没输入。而事务的rollback就是干这个用的。
FMDB下使用事务方式十分简单:
建立数据库db
FMDatabase *db = [FMDatabase databaseWithPath:path];
事务开始
[db beginTransaction];BOOL isRollback = NO;具体数据库操作可以包在@try中,如果捕获到异常就rollback
@try {// 数据库操作代码}@catch (NSException *exception) {isRollback = YES;[db rollback];}@finally {if (isRollback == NO) {[db commit];}}finally中判断,如果没有rollback就能提交。
因此工作二目前的最终结果是这样,没准以后还要改,比如C风格的字符串分割可以改成objC的tokenizer。
#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]; // 判断表是否已经存在 FILE *dbFile = fopen(databasePath, "r"); BOOL dbExisted = YES; if (!dbFile) { dbExisted = NO; } fclose(dbFile); FMDatabase *db = [[FMDatabase alloc] initWithPath:[NSString stringWithFormat:@"%s", databasePath]]; if ([db open] == NO) { NSLog(@"Failed to open database!"); return 1; } // 为了防止表格式有问题,因此先删去同名表,再创建相应表 if (dbExisted) [db executeUpdateWithFormat:@"drop table entity;"]; BOOL ret = [db executeUpdateWithFormat:@"create table entity(id integer primary key autoincrement, name TEXT not null unique, score integer, popularity integer);"]; if (ret != YES) { NSLog(@"Creating table entity failed!"); exit(1); } if (dbExisted) [db executeUpdateWithFormat:@"drop table tag;"]; ret = [db executeUpdateWithFormat:@"create table tag(id integer primary key autoincrement, name TEXT not null unique, score integer, popularity integer);"]; if (ret != YES) { NSLog(@"Creating table tag failed!"); exit(1); } if (dbExisted) [db executeUpdateWithFormat:@"drop table map;"]; ret = [db executeUpdateWithFormat:@"create table map(id integer primary key autoincrement, entity_id not null, tag_id integer);"]; if (ret != YES) { NSLog(@"Creating table map failed!"); exit(1); } NSDate *start = [NSDate date]; [db beginTransaction]; BOOL isRollback = NO; @try { // 用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 ++; } } @catch (NSException *exception) { isRollback = YES; [db rollback]; } @finally { if (isRollback == NO) { [db commit]; } } NSDate *end = [NSDate date]; double timeInterval = [end timeIntervalSinceDate:start]; NSLog(@"Time Consume: %lf", timeInterval); [db close]; return 0;}
0 0
- 工作二总结——objective-C中sqlite3数据库的处理(其三) sqlite3数据库事务的使用
- 工作二总结——objective-C中sqlite3数据库的处理(其一)
- 工作二总结——objective-C中sqlite3数据库的处理(其二)
- sqlite3数据库的使用
- sqlite3数据库的使用
- sqlite3数据库的使用
- C linux sqlite3 数据库的使用
- android中sqlite3数据库的使用
- 举例数据库sqlite3的使用
- 【iOS】数据库SQLite3的使用
- iOS Sqlite3 数据库的使用
- IOS sqlite3数据库的使用
- Linux 下的sqlite3数据库使用及Linux C的数据库编程总结
- objective-c sqlite3 最原始的使用
- Iphone——使用SQLite3进行简单的数据库操作
- SQLite3数据库的操作
- sqlite3数据库的心得
- sqlite3数据库的移植
- 第十一周项目一.3
- HppSlice:C++ 声明与实现的分离程序
- 1-11-1 - 输出字母版星号图
- java版的单向链表的基本操作
- QQ第三方登录
- 工作二总结——objective-C中sqlite3数据库的处理(其三) sqlite3数据库事务的使用
- unity3d技能冷却cd(第一篇)
- C#——列表框(listbox)的体验添加
- autocomplete使用手册
- 【概率论水题】COGS1487麻球繁衍
- Radar Installation(1328)
- 今年第几天?
- NSPredicate
- 存储过程