FMDB 是Objective-C上操作Sqlite的开源库,与原生的操作sqlite数据库相比,有以下几个优点:
操作方便、简单、代码优雅,易于维护;
线程安全,用着更放心,很少出现过锁死数据库文件以及Crash的现象。
FMDatabase不是线程安全的,一个FMDatabase对象一定不能在多线程中使用,为了保证线程安全,可以在FMDB中采取下面两种方式:
每个线程都创建一个FMDatabase对象,使用之前打开连接,用完关闭销毁;
使用FMDatabaseQueue来保证线程安全,一个FMDatabaseQueue的对象可以在多线程中共享使用。
使用FMDatabase时,一般这样来做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db" ]; if ([db open]) { FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable" ]; while ([s next]) { } [db close]; } db = nil ;
上面的这段代码是使用FMDatabase操作数据库的一个典型的使用方式,可以看到,其实我们关注的只是使用它来对数据库进行增删改查的操作,却每次都要写这些打开和关闭的操作,代码也显得臃肿,bad smell。用过Java中著名的Spring框架的同学都记得里面对数据库操作提供了一个Template的机制,比如JdbcTemplate、HibernateTemplate等,使用回调函数非常优雅的分离了创建连接、关闭连接和使用数据库连接操作数据库,下面就来模拟这个实现。 首先做个抽象,在上面代码的真正的逻辑中,我们只要拿到db变量就能满足我们的需要了,那么我们就把这一块抽象出来,在这里我们使用oc里的block来实现回调功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @implementation TWFmdbUtil + (void ) execSqlInFmdb:(void (^)(FMDatabase *db))block { NSString *dbPath = @"dbpath" ; FMDatabase *db = [FMDatabase databaseWithPath:dbPath]; if ([db open]) { @try { block(db); } @catch (NSException *exception) { NSLog (@"TWFmdbUtil exec sql exception: %@" , exception); } @finally { [db close]; } } else { NSLog (@"db open failed, path:%@, errorMsg:%@" , dbPath, [db lastError]); } db = nil ; } @end
现在使用的时候就能够像下面这样来实现了:
1 2 3 4 5 6 7 [TWFmdbUtil execSqlInFmdb:^(FMDatabase *db) { FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable" ]; while ([s next]) { } }];
这样的代码看起来是不是优雅多了呢?我们无需关心数据库的创建和关闭操作,只需要关心我们的业务逻辑就可以了。
历史总是惊人的相似,FMDatabaseQueue的使用就是采用这样的方式来处理的,来看一段fmdb主页上提供的一个例子:
1 2 3 4 5 6 7 8 9 10 11 FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; [queue inDatabase:^(FMDatabase *db) { [db executeUpdate:@"INSERT INTO myTable VALUES (?)" , [NSNumber numberWithInt:1 ]]; [db executeUpdate:@"INSERT INTO myTable VALUES (?)" , [NSNumber numberWithInt:2 ]]; [db executeUpdate:@"INSERT INTO myTable VALUES (?)" , [NSNumber numberWithInt:3 ]]; FMResultSet *rs = [db executeQuery:@"select * from foo" ]; while ([rs next]) { } }];
更多实例请移步FMDB在GitHub上的主页 或者访问@唐巧_boy 关于FMDB的这篇文章
Have Fun!