iOS中大量数据的存储,用的最多的是FMDB,小编在使用过程中遇到不少坑点。
一般情况下,数据库实例需要单例,像这样创建
static DBManager *_DB = nil;
+ (DBManager *)shareManager{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (_DB == nil) {
_DB = [[DBManager alloc] init];
}
});
return _DB;
}
- (id)init{
self = [super init];
if (self) {
NSString *path = [NSHomeDirectory() stringByAppendingString:@"/Documents/app.db"];
_dateBase = [[FMDatabase alloc] initWithPath:path];
if ([_dateBase open]) {
NSLog(@"打开数据库成功");
NSString *sql = @"create table if not exists appa(applicationId varchar(32),name varchar(128),iconUrl varchar(1024))";
if ([_dateBase executeUpdate:sql]) {
NSLog(@"创建表格成功");
}else{
NSLog(@"创建表格失败");
}
}else{
NSLog(@"打开数据库失败");
}
}
return self;
}
这样,<code>_dataBase</code>可以调用<code> executeQuery:(NSString *), ...</code>方法,返回<code>FMResultSet</code>结果集对象;除查询外的包括创建、删除表,增删改数据,都可以调用<code>executeUpdate:(NSString *), ...</code>方法,返回<code>BOOL</code>值。
// 查询SQL语句举例
NSString *sql = [NSString stringWithFormat:@"SELECT * FROM tableName WHERE idstr > %@ ORDER BY idstr DESC LIMIT 20;", @"123"];
// 执行SQL
FMResultSet *set = [_dataBase executeQuery:sql];
while (set.next) {
// 获取的数据
}
// 更新SQL语句举例
NSString *sql = [CREATE TABLE IF NOT EXISTS tableName (id integer PRIMARY KEY, name varchar(32) NOT NULL, idstr text NOT NULL];
// 执行SQL
BOOL isSuccess = [_dataBase executeUpdate:sql];
if (isSuccess) {
// 成功
}
然而,这会卡主线程,疯狂的向数据库插入数据,你会发现你的应用卡死了,开启多线程貌似可以解决问题,不一会儿数据库文件将会损坏,控制台也会打印错误信息,<code>database is bad</code>,打开数据库存储的路径,会看到带后缀的数据库损坏文件
使用多线程没有错,数据库文件的操作也需要线程安全,那么必须用到数据库队列<code>FMDatabaseQueue</code>,一般也是单例,调用方法<code>inDatabase:^(FMDatabase *db)block</code>或者<code>inTransaction:^(FMDatabase *db)block</code>,后者执行效率高
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:MessageDBPath];
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
NSString *sql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (id integer PRIMARY KEY, msg_id text);",tableName];
if ([db executeUpdate:sql]) {
NSLog(@"创表成功或存在表");
}else{
}];
开启事务后,显得方便很多,不用手动打开数据库,它会自动管理,把任务放在队列中执行,谁也碰不到前面的脚,每个人都很幸福
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:MessageDBPath];
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
NSString *sql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (id integer PRIMARY KEY, msg_id text);",tableName];
if ([db executeUpdate:sql]) {
NSLog(@"创表成功或存在表");
}else{
}];
});
像这样做,数据不会同步返回了,界面可以先放个菊花,待数据回调后,再主线程刷新UI,更多开启多线程的方法,可以参考我的另一篇博文 ios 使用多线程