在FMDB中,提供了3个核心类,需要程序员重点掌握。
FMDatabase:数据库类,所有的SQL语句都需要在数据库中执行。
FMResultSet:执行SELECT语句后,查询数据库的结果集。
FMDatabaseQueue:如果要在多线程上执行查询和更新,需要用到这个类。
如果需要创建一个数据库,只需要给FMDatabase类提供一个数据库文件存储的路径即可。在FMDatabase.h文件中,提供了databaseWithPath:方法,用于快速创建一个数据库。
+(instancetype)databaseWithPath:(NSString *)inPath;
在databaseWithPath:方法中,需要传入数据库所在路径,这个路径有3种情况:
提供一个系统路径。如果这个路径上没有数据库,则会创建一个新的数据库。一个空字符串@""。
在沙盒中的temporary文件夹中创建一个数据库,之后在数据库被关闭之后会被删除。
NULL。在内存中创建一个数据库,之后在数据库被关闭之后会被删除。
事务Transactions是数据库操作的单个工作单位。如果某一事务成功,则在该事务中进行的所有数据更改均会提交,成为数据库中永久的组成部分。若事务遇到错误,则必须取消或回滚,所有数据均被更改清除。FMDatabase通过begin/end语句来开始和提交一个事务。
// 开始执行事务。
-(BOOL)beginTransaction;
// 提交事务。
-(BOOL)commit;
// 事务回滚。
-(BOOL)rollback;
在FMDB中,把对数据库的操作合并为两类。
第一类是查询操作,即使用SELECT语句执行的操作,查询操作的特点是会返回查询结果,继而对查询结果做进一步的处理;
第二类是更新操作,所有非SELECT语句的都可以看成是更新操作,包括CREATE、UPDATE、INSERT、ALTER、DELETE、DROP等语句。
// 更新操作
-(BOOL)executeUpdate:(NSString *)sql, ...;
执行更新语句会返回一个BOOL值。如果是YES则表示更新成功,如果是NO则表示更新失败。
可以调用lastErrorMessage和lastErrorCode方法来获取失败的原因。
-(NSString *)lastErrorMessage;
-(int)lastErrorCode;
// 查询操作
-(FMResultSet *)executeQuery:(NSString *)sql, ...;
执行查询语句之后,如果成功会返回一个FMResultSet对象。如果失败会返回nil,
同样可以调用lastErrorMessage和lastErrorCode方法来获取失败的原因。
// 为了遍历查询的结果集,需要使用while()循环。并且调用FMResultSet类的next方法,从一条记录移动到下一条记录。例如:
FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"];
while ([s next]) {
//
}
FMResultSet有很多方法来获取对应的值,主要包括两类:
第一类是通过列名获取对应的值;
第二类是通过列序号获取对应的值。
通常来说不用手动调用FMResultSet的close方法。FMResultSet对象销毁或者数据库关闭时会自动调用FMResultSet的-close方法。
当需要执行多条SQL语句时,FMDB也提供了快捷方法,并不需要一条一条执行。可以通过FMDatabase类中的executeStatements:方法来执行多条语句。
-(BOOL)executeStatements:(NSString *)sql;
-(BOOL)executeStatements:(NSString *)sql withResultBlock:(FMDBExecuteStatementsCallbackBlock)block;
// 示例
在编写SQL语句时不必手动去拼接,可以使用标准的SQLite绑定语法:
INSERT INTO myTable VALUES (?, ?, ?, ?)
// ?表示一个占位符,会被后续传进来的值所替代。
在使用线程安全(FMDatabaseQueue)时,不要创建一个单例数据库,然后在多个线程中使用。如果坚持要这么做,系统最终会崩溃。如果一定要在多个线程中使用,可以在每个线程中创建一个FMDatabase对象。另外,还有一个更好的方法就是使用FMDatabaseQueue类。用户可以生成一个FMDatabaseQueue单例,然后在多线程中使用它,FMDatabaseQueue会负责同步和协调多线程。
// 创建一个FMDatabaseQueue队列。
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
//
[queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @1];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @2];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @3];
FMResultSet *rs = [db executeQuery:@"select * from maTable"];
while ([re next]) {
}
}]