lipengfei 2013-05-07
SQLite(http://www.sqlite.org/docs.html)是一个轻量级的关系数据库。iOSSDK很早就支持了SQLite,在使用时,只需要加入libsqlite3.dylib依赖以及引入sqlite3.h头文件即可。但是,原生的SQLiteAPI在使用上相当不友好,在使用时,非常不便。于是,开源社区中就出现了一系列将SQLiteAPI进行封装的库,而FMDB(https://github.com/ccgus/fmdb)则是开源社区中的优秀者。
FMDB在使用上相当方便。以下是一个简单的例子:
1234567891011
NSString*docsdir=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)lastObject];NSString*dbpath=[docsdirstringByAppendingPathComponent:@"user.sqlite"];FMDatabase*db=[FMDatabasedatabaseWithPath:dbpath];[dbopen];FMResultSet*rs=[dbexecuteQuery:@"select*frompeople"];while([rsnext]){NSLog(@"%@%@",[rsstringForColumn:@"firstname"],[rsstringForColumn:@"lastname"]);}[dbclose];
可以看到,使用FMDB后的数据库代码清晰明了,比原生的API优雅多了。另外,FMDB同时兼容ARC和非ARC工程,会自动根据工程配置来调整相关的内存管理代码。
使用说明
该使用说明主要翻译自fmdb的github项目说明文档:https://github.com/ccgus/fmdb
引入相关文件
首先将FMDB从github上clone下来,然后将以下文件copy到你的工程中:
12345678910
FMDatabase.hFMDatabase.mFMDatabaseAdditions.hFMDatabaseAdditions.mFMDatabasePool.hFMDatabasePool.mFMDatabaseQueue.hFMDatabaseQueue.mFMResultSet.hFMResultSet.m
建立数据库
建立数据库只需要如下一行即可,当该文件不存在时,fmdb会自己创建一个。如果你传入的参数是空串:@””,则fmdb会在临时文件目录下创建这个数据库,如果你传入的参数是NULL,则它会建立一个在内存中的数据库。
1
FMDatabase*db=[FMDatabasedatabaseWithPath:@"/tmp/tmp.db"];
打开数据库
使用如下语句,如果打开失败,可能是权限不足或者资源不足。通常打开完操作操作后,需要调用close方法来关闭数据库。
12345678
if(![dbopen]){//errorreturn;}//someoperation//...[dbclose];
执行更新操作
除了Select操作之外,其它的都是更新操作。更新操作使用如下方法,如果有错误,可以用error参数中获得。
1
-[FMDatabaseexecuteUpdate:error:withArgumentsInArray:orVAList:]
执行查询操作
查询操作示例如下。注意:即使操作结果只有一行,也需要先调用FMResultSet的next方法。
123456789
FMResultSet*s=[dbexecuteQuery:@"SELECT*FROMmyTable"];while([snext]){//retrievevaluesforeachrecord}FMResultSet*s=[dbexecuteQuery:@"SELECTCOUNT(*)FROMmyTable"];if([snext]){inttotalCount=[sintForColumnIndex:0];}
FMDB提供如下多个方法来获取不同类型的数据:
1234567891011
intForColumn:longForColumn:longLongIntForColumn:boolForColumn:doubleForColumn:stringForColumn:dateForColumn:dataForColumn:dataNoCopyForColumn:UTF8StringForColumnIndex:objectForColumn:
通常情况下,你并不需要关闭FMResultSet,因为相关的数据库关闭时,FMResultSet也会被自动关闭。
数据参数
通常情况下,你可以按照标准的SQL语句,用?表示执行语句的参数,如:
1
INSERTINTOmyTableVALUES(?,?,?)
然后,可以我们可以调用executeUpdate方法来将?所指代的具体参数传入,通常是用变长参数来传递进去的,如下:
12
NSString*sql=@"insertintoUser(name,password)values(?,?)";[dbexecuteUpdate:sql,user.name,user.password];
这里需要注意的是,参数必须是NSObject的子类,所以象int,double,bool这种基本类型,需要封装成对应的包装类才行,如下所示:
1234
//错误,42不能作为参数[dbexecuteUpdate:@"INSERTINTOmyTableVALUES(?)",42];//正确,将42封装成NSNumber类[dbexecuteUpdate:@"INSERTINTOmyTableVALUES(?)",[NSNumbernumberWithInt:42]];
线程安全
如果我们的app需要多线程操作数据库,那么就需要使用FMDatabaseQueue来保证线程安全了。切记不能在多个线程中共同一个FMDatabase对象并且在多个线程中同时使用,这个类本身不是线程安全的,这样使用会造成数据混乱等问题。
使用FMDatabaseQueue很简单,首先用一个数据库文件地址来初使化FMDatabaseQueue,然后就可以将一个闭包(block)传入inDatabase方法中。在闭包中操作数据库,而不直接参与FMDatabase的管理。
12345678910111213141516171819202122232425262728
//创建,最好放在一个单例的类中FMDatabaseQueue*queue=[FMDatabaseQueuedatabaseQueueWithPath:aPath];//使用[queueinDatabase:^(FMDatabase*db){[dbexecuteUpdate:@"INSERTINTOmyTableVALUES(?)",[NSNumbernumberWithInt:1]];[dbexecuteUpdate:@"INSERTINTOmyTableVALUES(?)",[NSNumbernumberWithInt:2]];[dbexecuteUpdate:@"INSERTINTOmyTableVALUES(?)",[NSNumbernumberWithInt:3]];FMResultSet*rs=[dbexecuteQuery:@"select*fromfoo"];while([rsnext]){//…}}];//如果要支持事务[queueinTransaction:^(FMDatabase*db,BOOL*rollback){[dbexecuteUpdate:@"INSERTINTOmyTableVALUES(?)",[NSNumbernumberWithInt:1]];[dbexecuteUpdate:@"INSERTINTOmyTableVALUES(?)",[NSNumbernumberWithInt:2]];[dbexecuteUpdate:@"INSERTINTOmyTableVALUES(?)",[NSNumbernumberWithInt:3]];if(whoopsSomethingWrongHappened){*rollback=YES;return;}//etc…[dbexecuteUpdate:@"INSERTINTOmyTableVALUES(?)",[NSNumbernumberWithInt:4]];}];
工具
为了查看Sqlite中的数据,一个好的图形化界面的数据库管理程序是必不可少的。mysql有phpMyAdmin,那么sqlite呢?
我主要使用的是Firefox的一个名为SQLiteManager的插件,安装此插件后,可以直接打开后缀名为sqlite的数据库文件。SQLiteManager提供一个图形化的界面来执行数据查询或更改操作。如下图所示: