C语言iOS学习笔记17-FMDB你好!

上一样省自我早就介绍了SQLite的简便以,不了解之得提前去押一下iOS学习笔记16-数据库SQLite,这节咱们来讲下FMDB。

一、FMDB介绍

FMDB是一致种植第三正的开源库,FMDB就是对SQLite的API进行了包,加上了面向对象的思量,让咱们不用采取繁琐的C语言API函数,比从直接操作SQLite更加有益于。

FMDB优点:
  • 使用起来更面向对象,省去了不少烦劳、冗余的C语言代码
  • 相比苹果自带的CoreData框架,更加轻量级和活
  • 提供大多线程安全,有效地防数据错乱,原来的SQLite不是线程安全之
FMDB缺点:

因为凡OC语言封装的,失去了SQLite原来的跨平台性

咱们设动FMDB需要之步子:
  1. 路面临上加libsqlite3库房底依
  1. 导入FMDB源码:
    下载FMDB的源代码,将代码文件拖入工程
  2. #import导入FMDB的条文件"FMDatabase.h"

二、FMDB使用

动用FMDB前,需要事先了解下3只第一类:
  1. FMDatabase : 一个单一的SQLite数据库,用于实践SQL语句。
  1. FMResultSet :执行查询一个FMDatabase结果集。
  2. FMDatabaseQueue :在多单线程来实施查询与创新时会使用是看似。
诚如的FMDB数据库操作发生:
  1. 缔造数据库
  1. 打开数据库、关闭数据库
  2. 施行更新的SQL语句
  3. 实践查询的SQL语句

1.创造数据库

创建数据库使用及之是FMDatabase的切近措施:
/*
 1. 如果该路径下已经存在该数据库,直接获取该数据库;
 2. 如果不存在就创建一个新的数据库;
 3. 如果传@"",会在临时目录创建一个空的数据库,当数据库关闭时,数据库文件也被删除;
 4. 如果传nil,会在内存中临时创建一个空的数据库,当数据库关闭时,数据库文件也被删除;
*/
+ (FMDatabase *)databaseWithPath:(NSString *)filePath;
下面是实例:
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObject; 
NSString *filePath = [path stringByAppendingPathComponent:@"FMDB.db"];
FMDatabase *database = [FMDatabase databaseWithPath:filePath];

只顾:这里创办数据库,并无会见打开数据库,和SQLite有点区别

2. 打开数据库、关闭数据库

开辟和关闭数据库很简短:
/* 打开数据库,成功返回YES,失败返回NO */
- (BOOL)open;
/* 关闭数据库,成功返回YES,失败返回NO */
- (BOOL)close;

3. 尽更新的SQL语句

在FMDB中,除查询以外的持有操作,都叫作“更新”。
例如createdropinsertupdatedelete对等SQL语句发号施令还是创新操作。

实践更新的SQL语句以的常用方法:
/* 执行更新的SQL语句,字符串里面的"?",依次用后面的参数替代,必须是对象,不能是int等基本类型 */
- (BOOL)executeUpdate:(NSString *)sql,... ;
/* 执行更新的SQL语句,可以使用字符串的格式化进行构建SQL语句 */
- (BOOL)executeUpdateWithFormat:(NSString*)format,... ;
/* 执行更新的SQL语句,字符串中有"?",依次用arguments的元素替代 */
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments;
下的4种下等:
/* 1. 直接使用完整的SQL更新语句 */
[database executeUpdate:@"insert into mytable(num,name,sex) values(0,'liuting','m');"];

NSString *sql = @"insert into mytable(num,name,sex) values(?,?,?);";
/* 2. 使用不完整的SQL更新语句,里面含有待定字符串"?",需要后面的参数进行替代 */
[database executeUpdate:sql,@0,@"liuting",@"m"];
/* 3. 使用不完整的SQL更新语句,里面含有待定字符串"?",需要数组参数里面的参数进行替代 */
[database executeUpdate:sql 
   withArgumentsInArray:@[@0,@"liuting",@"m"]];

/* 4. SQL语句字符串可以使用字符串格式化,这种我们应该比较熟悉 */
[database executeUpdateWithFormat:@"insert into mytable(num,name,sex) values(%d,%@,%@);",0,@"liuting","m"];
运用实例:
- (BOOL)createTable {
    NSString *sqlStr = @"create table mytable(num integer,name varchar(7),sex char(1),primary key(num));";
    BOOL res = [_database executeUpdate:sqlStr];
    if (!res) {
        NSLog(@"error when creating database table");
        [_database close];
    }
    return res;
}

4. 推行查询的SQL语句

查询SQL语句一般仰仗select

下是常用实现方式:
/* 执行查询SQL语句,返回FMResultSet查询结果 */
- (FMResultSet *)executeQuery:(NSString*)sql, ... ;
- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ... ;
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments;
处理结果FMResultSet的常用方法:
/* 获取下一个记录 */
- (BOOL)next;
/* 获取记录有多少列 */
- (int)columnCount;
/* 通过列名得到列序号,通过列序号得到列名 */
- (int)columnIndexForName:(NSString *)columnName;
- (NSString *)columnNameForIndex:(int)columnIdx;
/* 获取存储的整形值 */
- (int)intForColumn:(NSString *)columnName;
- (int)intForColumnIndex:(int)columnIdx;
/* 获取存储的长整形值 */
- (long)longForColumn:(NSString *)columnName;
- (long)longForColumnIndex:(int)columnIdx;
/* 获取存储的布尔值 */
- (BOOL)boolForColumn:(NSString *)columnName;
- (BOOL)boolForColumnIndex:(int)columnIdx;
/* 获取存储的浮点值 */
- (double)doubleForColumn:(NSString *)columnName;
- (double)doubleForColumnIndex:(int)columnIdx;
/* 获取存储的字符串 */
- (NSString *)stringForColumn:(NSString *)columnName;
- (NSString *)stringForColumnIndex:(int)columnIdx;
/* 获取存储的日期数据 */
- (NSDate *)dateForColumn:(NSString *)columnName;
- (NSDate *)dateForColumnIndex:(int)columnIdx;
/* 获取存储的二进制数据 */
- (NSData *)dataForColumn:(NSString *)columnName;
- (NSData *)dataForColumnIndex:(int)columnIdx;
/* 获取存储的UTF8格式的C语言字符串 */
- (const unsigned cahr *)UTF8StringForColumnName:(NSString *)columnName;
- (const unsigned cahr *)UTF8StringForColumnIndex:(int)columnIdx;
/* 获取存储的对象,只能是NSNumber、NSString、NSData、NSNull */
- (id)objectForColumnName:(NSString *)columnName;
- (id)objectForColumnIndex:(int)columnIdx;
使实例:
- (NSArray *)getResultFromDatabase{
    //执行查询SQL语句,返回查询结果
    FMResultSet *result = [_database 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];
    }
    return array;
}

其三、 多线程安全FMDatabaseQueue

FMDatabase以此仿佛是线程不安全的,如果在差不多个线程同时利用一个FMDatabase实例,会促成数据错乱问题。
为确保线程安全,FMDB提供方便快捷的FMDatabaseQueue看似,要利用这仿佛,需要#import导入头文件"FMDatabaseQueue.h"FMDatabaseQueue类似的操作多还和FMDatabase很相似

1. 创建

NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObject; 
NSString *filePath = [path stringByAppendingPathComponent:@"FMDB.db"];
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];

2. 操作数据库

[queue inDatabase:^(FMDatabase*db) {
    //FMDatabase数据库操作
}];
动实例:
[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];
    }
}];

四、 事务

事务,是凭借当单个逻辑工作单元执行的相同多重操作,要么完全地履行,要么完全地无执。

设想一个面貌,比如您要是创新数据库的大方数码,我们用确保所有的数码更新成功,才以这种创新方案,如果在更新中出现错误,就未可知利用这种翻新方案了,如果我们无应用工作,我们的创新操作直接针对每个记录生效,万一遇到更新错误,已经更新的多少怎么收拾?难道我们如果一个一个去探寻出来修改回来吗?怎么亮原来的数是哪些的也?这个上便需运用事务实现。

用用工作放到FMDB受到失说并无是盖只有FMDB才支撑工作,而是因FMDB用那卷入成了几乎独方式来调用,不用自己写对应的SQL而已。

SQLite进行工作的SQL语句:
只要在执行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使用工作的不二法门:
//多线程事务 
- (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的时候,事务回退,如果最后*rollback为NO,事务提交
                *rollback = YES;
                 return; 
            } 
        }
     }]; 
}

发觉一个深好的关于FMDB文档《FMDB类的求证文档》,里面虽然是英文的,但是列出了具备的FMDB类的法门,很过硬!下面是截图:

FMDB类说明文档

有什么问题可以以江湖评论区中提出,一起学习,O(∩_∩)O哈!