From: http://vin-zhou.github.io/2016/11/18/FMDB%E4%BD%BF%E7%94%A8%E6%9C%AD%E8%AE%B0/
文章目录
- 前言
- 安装
- 使用
- 创建数据库
- 打开数据库
- 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连接关掉后将被自动释放。
1 2 3 4 5 6 7 8
| NSArray* array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString* documents = [array objectAtIndex:0]; NSString* path = [documents stringByAppendingPathComponent:@"test.db"]; FMDatabase* db = [FMDatabase databaseWithPath:path];
|
打开数据库
在使用之前,必须先调用open函数,保证数据库被打开。当资源不足或权限不够时,可能会open失败,这时需要返回,无法后续操作。
1 2 3 4 5 6 7
| if (![db open]) { db = nil; return; }
|
执行更新
任何不以SELECT开头的SQL操作都属于更新操作,包括 CREATE, UPDATE, INSERT, ALTER, COMMIT, BEGIN, DETACH, DELETE, DROP, END, EXPLAIN, VACUUM, 以及 REPLACE 等,通过-executeUpate...
这种方法来执行,执行更新正确会返回YES,否则返回NO。
1 2 3 4 5
| 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方法来查询为何执行失败。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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使用事务:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| -(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中的操作放到
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| [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 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 } } }] }
|
参考
iOS学习笔记17-FMDB你好!