From: http://vin-zhou.github.io/2016/11/18/FMDB%E4%BD%BF%E7%94%A8%E6%9C%AD%E8%AE%B0/
文章目录
-
- 前言
-
- 安装
-
- 使用
-
- 创建数据库
-
- 打开数据库
1. 5.1. 执行更新
- 打开数据库
-
- 执行查询
-
- 关闭数据库
-
- 事务
-
- 使用线程安全的FMDatabaseQueue
-
- 参考
前言
[FMDB][1] 是一款使用Objective-C对SQLite进行封装的优秀的第三方框架,加上了面向对象的思想。
[1]:
优点:
- 使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码
- 对比苹果自带的CoreData框架,更加轻量级和灵活
- 提供多线程安全,有效地防止数据混乱,原来的SQLite不是线程安全的
- 支持使用Swift调用
缺点:
- 因为是OC语言封装的,失去了SQLite原来的跨平台性
FMDB的方方面面在Github上已经交代的比较明白,这里自己再总结摘要一下。
安装
- 在Github上下载FMBDB源码,将文件拖入工程
- 在项目target的Build Phases->Link Bianry With Libraries中添加libsqlite3.tbd依赖库
- #import “FMDatabase.h”
使用
主要包含如下三个类:
- FMDatabase - 代表一个SQLite数据库,用来在单一线程中执行SQL语句,线程不安全。
- FMResultSet - 代表执行一次查询后的结果。
- FMDatabaseQueue - 用于多线程操作数据库的查询和更新,线程安全。
创建数据库
支持传入3种文件路径:
- 传入真实的文件系统路径,如不存在该文件,将自动创建;
- 传入空字符串@””. 创建一个本地的临时数据库,当FMDatabase连接关掉后将被自动删除;
- 传入NULL.创建一个in-memory数据库,当FMDatabase连接关掉后将被自动释放。
NSArray* array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documents = [array objectAtIndex:0];
NSString* path = [documents stringByAppendingPathComponent:@"test.db"];
FMDatabase* db = [FMDatabase databaseWithPath:path];
打开数据库
在使用之前,必须先调用open函数,保证数据库被打开。当资源不足或权限不够时,可能会open失败,这时需要返回,无法后续操作。
if (![db open]) {
db = nil;
return;
}
执行更新
任何不以SELECT开头的SQL操作都属于更新操作,包括 CREATE, UPDATE, INSERT, ALTER, COMMIT, BEGIN, DETACH, DELETE, DROP, END, EXPLAIN, VACUUM, 以及 REPLACE 等,通过-executeUpate...
这种方法来执行,执行更新正确会返回YES,否则返回NO。
BOOL updateResult = [db executeUpdate:@"CREATE TABLE myTable (num integer, name varchar(7), sex char(1), primary key(num))"];
if (!updateResult) {return;}
updateResult = [db executeUpdate:@"INSERT INTO myTable(num, name, sex) values(?,?,?)", @0, @"hha", @"m"];
执行查询
一个SELECT查询语句将通过-executeQuery...
这种方法来执行,如果正确,返回一个FMResultSet对象,否则返回nil。必须使用-lastErrorMessage和-lastErrorCode方法来查询为何执行失败。
FMResultSet* result = [db executeQuery:@"SELECT * FROM myTable"];
NSMutableArray *array = [NSMutableArray array];
while ([result next]) {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
int num = [result intForColumn:@"num"];
NSString *name = [result stringForColumn:@"name"];
NSString *sex = [result stringForColumn:@"sex"];
dict[@"num"] = @(num);
dict[@"name"] = name;
dict[@"sex"] = sex;
[array addObject:dict];
}
关闭数据库
调用close方法即可。
事务
事务,是指作为单个逻辑工作单元执行的一系列操作,要么完整地执行,要么完全地不执行。
想象一个场景,比如你要更新数据库的大量数据,我们需要确保所有的数据更新成功,才采取这种更新方案,如果在更新期间出现错误,就不能采取这种更新方案了,如果我们不使用事务,我们的更新操作直接对每个记录生效,万一遇到更新错误,已经更新的数据怎么办?难道我们要一个一个去找出来修改回来吗?怎么知道原来的数据是怎么样的呢?这个时候就需要使用事务实现。
SQLite进行事务处理:
- 只要在执行SQL语句前加上以下的SQL语句,就可以使用事务功能了:
- 开启事务的SQL语句,”begin transaction;”
- 进行提交的SQL语句,”commit transaction;”
- 进行回滚的SQL语句,”rollback transaction;”
FMDatabase使用事务:
-(void)transaction {
[self.database beginTransaction];
BOOL isRollBack = NO;
@try {
for (int i = 0; i<500; i++) {
NSNumber *num = @(i+1);
NSString *name = [[NSString alloc] initWithFormat:@"student_%d",i];
NSString *sex = (i%2==0)?@"f":@"m";
NSString *sql = @"insert into mytable(num,name,sex) values(?,?,?);";
BOOL result = [database executeUpdate:sql,num,name,sex];
if ( !result ) {
NSLog(@"插入失败!");
return;
}
}
}
@catch (NSException *exception) {
isRollBack = YES;
[self.database rollback];
}
@finally {
if (!isRollBack) {
[self.database commit];
}
}
}
使用线程安全的FMDatabaseQueue
不能在线程间共用一个FMDatabase, 否则会造成数据混乱! 如果需要使用多线程,应该使用线程安全的FMDatabaseQueue. (#import “FMDatabaseQueue.h” 即可)
FMDatabaseQueue的操作与FMDatabase非常类似,如
- 创建
FMDatabaseQueue* queue = [FMDatabaseQueue databaseQueueWithPath: aPath];
- 操作
将FMDatabase中的操作放到
[queue inDatabase:^(FMdatabase*db){
}];
即可。
[queue inDatabase:^(FMDatabase*db) {
NSString *sqlStr = @"insert into mytable(num,name,sex) values(4,'xiaoming','m');";
BOOL result = [db executeUpdate:sqlStr];
if (!result) {
NSLog(@"error when insert into database table");
[db close];
}
}];
* 事务
- (void)transactionByQueue {
[self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
for (int i = 0; i<500; i++) {
NSNumber *num = @(i+1);
NSString *name = [[NSString alloc] initWithFormat:@"student_%d",i];
NSString *sex = (i%2==0)?@"f":@"m";
NSString *sql = @"insert into mytable(num,name,sex) values(?,?,?);";
BOOL result = [db executeUpdate:sql,num,name,sex];
if ( !result ) {
*rollback = YES;
return;
}
}
}];
}
文章评论