FMDB使用

框架地址:[https://github.com/ccgus/fmdb]

  • 下载框架


    Snip20160912_6.png
  • 首先要明白框架中几个重要的类

    • FMDatabase 代表一个数据库 并且可以使用它执行sqlite语句
    • FMDatabaseQueue 是线程安全的存储跟读取数据 这里有一个概念---事物
    • FMResultSet 结果集 从数据库中读取数据的集合
  • 使用之前会发现编译报错,需要先在Build Phases->Link Binary With Libraries->导入libsqlite3.tbd 再次编译就👌

FMDatabase

  • 首先我们我们不考虑线程安全下使用FMDatabase来创建数据库实现离线缓存
    • 导入#import "FMDB.h"
// 1.获得数据库路径
     NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"daba.sqlist"];
    // 2.创建数据对象
    FMDatabase *dataBase = [FMDatabase databaseWithPath:path];
    
    // 3.打开数据库的时候首先判断当前数据库是否存在, 如果不存储在就创建一个并打开, 如果存储在那么就不创建直接打开
    BOOL isSuccess = [dataBase open];
    if (!isSuccess) {
        NSLog(@"打开数据库失败");
    }else{
        NSLog(@"打开数据库成功");
    
    }
}
  • 创建好数据库之后,接下来就是根据我们的需求在数据库中中创建表了,一个数据库可以创建多张表, 一张表包含多个字段,也就是对应表的column, 表是有row跟column构成, 有点类似Excle表

  • 细节不多说 创建一个完整的字段表

// 数据库前提是open状态
    /**
     * PRIMARY KEY 主键
     * AUTOINCREMENT 自动增量
     * UNIQUE 唯一
     * DEFAULT 默认值
     *  @param INTEGER 整型
     *  @param TEXT    文本
     *  @param REAL    浮点型
     *  @param
     *  @param BLOB    二进制
     */
    BOOL isSuccess = [dataBase executeUpdate:@"CREATE TABLE IF NOT EXIST t_table (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, age INTEGER  NOT NULL UNIQUE DEFAULT 0, score REAL NOT NULL unique, data BLOB);"];
    
    if (!isSuccess) {
        NSLog(@"创建表成功");
    }else{
        NSLog(@"创建表失败");
        
    }
  • 表创建完成了,接下来就是我们利用FMDatabase对象要插入数据了, 这里我们了解一下插入数据的常见3中写法
    /**此种方式后面拼接的参数必须为对象 不可以为int double等基本数据类型*/
    [dataBase executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
    /**此种方式后面拼接的参数可以为int double等基本数据类型 因为是使用的占位符*/
    [dataBase executeUpdateWithFormat:@"insert into t_table(name, age, score, data) values(%@, %d , %f, %@)", @"jake", 12, 91.0, [NSData data]];
    /**此种方式后面拼接的参数必须为对象 不可以为int double等基本数据类型 将对象依次防近视数组*/
    [dataBase executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)" withArgumentsInArray:@[@12, @91.0, [NSData data]]];

-注意 当我们存储表中BLOB 对应的字段如果为字典的时候,这个时候我们不应该把字典往里存,应当使用[NSKeyedArchiver archivedDataWithRootObject:<#(nonnull id)#>] 将字典转换成NSData类型, 这样当我们取出数据的时候取出的是NSData类型,再将NSData类型数据通过[NSKeyedUnarchiver unarchiveObjectWithData:<#(nonnull NSData *)#>];反归档得到就是字典,如果直接存字典,从数据数据库中取出的是字符串, 字典装模型时候会报错

  • 下面再说一下查表, 更行表 删除表数据就不说了,跟插入数据一样 自己研究
  • 书写格式几乎相同 就是返回结果是FMResultSet类型(结果集), 这时候根据遍历结果集取出每一条数据
    /**此种方式后面拼接的参数必须为对象 不可以为int double等基本数据类型*/
    [dataBase executeQuery:@"select *From t_table;"];
    /**此种方式后面拼接的参数可以为int double等基本数据类型 因为是使用的占位符*/
    [dataBase executeQueryWithFormat:@"SELECT name, age, score from t_table where name = %@", @"jake"];
    /**此种方式后面拼接的参数必须为对象 不可以为int double等基本数据类型 将对象依次防近视数组*/
    [dataBase executeQuery:@"select *from t_table where age > ?" withArgumentsInArray:@[@12]];
  • 拿查整个表的全部数据为例
 FMResultSet * resultSet = [dataBase executeQuery:@"select *From t_table;"];
    while ([resultSet next]) {
        // 通过字段获取 文本数据
        [resultSet stringForColumn:@"name"];
        // 也可以通过Column来获取
        [resultSet stringForColumnIndex:2];
        
        // 通过字段获取 对象数据
        [resultSet objectForColumnName:@"dict"];
        
    }
  • 关于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;

FMDatabaseQueue

  • 如果项目中开启多个线程同时访问一个数据库的时候,需要考虑到线程安全的问题了,那么就要使用这个类来对数据库操作了, 那么我们还要理解一个概念 事物 常说开启事物 提交事物 回滚事物 是什么意思呢? 为什么需要开启事物呢

  • 说个情形就明白了,加入我们像一个数据库表中插入一百条数据, 我们可能会执行一百条SQLite语句,如果当我们执行到一半的时候出错了,那么我们需要回滚, 让之前执行的的数据恢复之前数据,也就是一句话,我们需要所有的语句都执行成功才生效,那么我们就需要开启事物,当确定所有的语句都执行成功就提交事物, 如果中途出错,那么就回滚事物

  • 首先我们不开启事物,就线程安全来使用FMDB

// 1.获得数据库路径
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"daba.sqlist"];
    
    // 创建FMDatabaseQueue 同时会创建数据库 如果数据库不存在
    FMDatabaseQueue *baseQueue = [FMDatabaseQueue databaseQueueWithPath:path];
  • 当我们对数据库进行CRUDde的时候调用- (void)inDatabase:(void (^)(FMDatabase *db))block, 在block回调给我的FMDatabase对象进行操作 ,操作跟上面一样的 例如
[baseQueue inDatabase:^(FMDatabase *db) {
        // 打开数据库 创建表
        BOOL isSuccess = [db open];
        if (!isSuccess) {
            NSLog(@"打开数据库失败");
        }else{
            NSLog(@"打开数据库成功");
            
            // 插入数据
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
        }
        
    }];
  • 使用一下开启事物, 加入我们插入同时插入十条数据
// 1.获得数据库路径
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"daba.sqlist"];
    
    // 创建FMDatabaseQueue 同时会创建数据库 如果数据库不存在
    FMDatabaseQueue *baseQueue = [FMDatabaseQueue databaseQueueWithPath:path];
    
    [baseQueue inDatabase:^(FMDatabase *db) {
        // 打开数据库 创建表
        BOOL isSuccess = [db open];
        if (!isSuccess) {
            NSLog(@"打开数据库失败");
        }else{
            NSLog(@"打开数据库成功");
            
            // 开启事物
            [db beginTransaction];
            
            // 插入数据
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
            // 也可以在中途回滚 就是该次对数据库的操作不生效 通常中途一般不回滚
            [db rollback];
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
            [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
            
            // 提交事物
            [db commit];
            
        }
        
    }];
  • 其实FMDB内部已经帮我们封装好,只需要调用FMDatabaseQueue对象方法 - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block
[baseQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {

        [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
        [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
        [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
        [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
        [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
        [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
        // 如果中途想回滚 就这样操作
        *rollback = YES;
        [db rollback];
        [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
        [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
        [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
        [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
        [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
        [db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
    }];
  • 下班了,不写了,大家如果发现有误,谢谢反馈给我😝😄
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容