FMDB的简单概述

这篇博客主要是用来简单介绍一下FMDB的基础用法,涉及到简单的增删改查

一:FMDB介绍

FMDB是一种第三方的开源库,FMDB就是对SQLite的API进行了封装,加上了面向对象的思想,简单来说就是让我们能更方遍的操作SQLite更加方便。

FMDB优点:

  • 使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码
  • 对比苹果自带的CoreData框架,更加轻量级和灵活
  • 提供多线程安全,有效地防止数据混乱,原来的SQLite不是线程安全的

使用FMDB需要的步骤:

  1. 项目中添加libsqlite3库的依赖
  2. 推荐直接使用cocoapods导入到项目当中
  3. 在需要用到的类中导入FMDB的头文件 #import "FMDatabase.h"

二:FMDB的使用

FMDB的具体步骤我简单的归类为一下几个小点,下面会一一描述相应的citydb就是城市的数据库:

  1. 创建数据库
  2. 打开数据库
  3. 创建相应的库表
  4. 对库表进行操作
  5. 对查出数据的解析
  6. 关闭数据库

1:创建数据库的方法

根据FMDB官方的注解翻译过来的意思就是

/*
 1. 这个文件不一定必须存在沙盒中,所以如果已经存在的话就直接使用,不存在就会帮你创建一个;
 2. 你可以选择直接传空的字符串,那么系统会在临时目录创建一个空的数据库,当数据库关闭时,该数据库文件也被删除;
 3. 如果传nil,会在内存中临时创建一个空的数据库,当数据库关闭时,数据库文件也被删除;
*/
+ (FMDatabase *)databaseWithPath:(NSString *)filePath;

相应的实现方法是:

NSString *DocumentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *dbPath = [DocumentPath stringByAppendingPathComponent:@"data.db"];
FMDatabase *citydb = [FMDatabase databaseWithPath:dbPath];

2:打开数据库

/*
打开数据库,一般用法是在查询语句之前调用一下,返回值是BOOL类型,这个BOOL的意思是告诉你这次打开是否成功,然后打开成功以后你就能对你的数据库进行操作了
*/
[citydb open];

3:创建库表

这里额外说明一下,[citydb executeUpdate:sql];这句话用的是executeUpdate方法,因为添加库表可以理解为更新数据库的行为,所以executeUpdate是可行的,同时用executeStatements方法也是同样可行的,executeStatements简单理解就是让数据库运行这个方法里的行为。

    FMDatabase * db = [FMDatabase databaseWithPath:self.dbPath];
    if ([db open]) {
        NSString *sql = @"create table if not exists city(cityName text, cityId text, userId text);";
        [citydb executeUpdate:sql];
    }
    

4:对数据库进行操作

/* 执行更新的SQL语句,字符串里面的"?",依次用后面的参数替代,必须是对象,不能是int等基本类型 */
- (BOOL)executeUpdate:(NSString *)sql,... ;
/* 执行更新的SQL语句,可以使用字符串的格式化进行构建SQL语句 */
- (BOOL)executeUpdateWithFormat:(NSString*)format,... ;
/* 执行更新的SQL语句,字符串中有"?",依次用arguments的元素替代 */
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments;

下面我在列举一下简单的增删改查四个方法

增加字段到city

FMDatabase * db = [FMDatabase databaseWithPath:self.dbPath];
    if ([db open]) {
        BOOL res = NO;
        NSDictionary *cityDic = @{@"杭州":@"1",@"上海":@"2",@"宁波":@"3",@"温州":@"4",@"台州":@"5",@"湖州":@"6",@"绍兴":@"7",@"金华":@"8"};
        for (NSString *key in cityDic.allKeys) {
            NSString *sqlStr = [NSString stringWithFormat:@"insert into city(cityName,cityId,userId)values('%@','%@','%@')",key,cityDic[key],@"123"];
            res = [db executeUpdate:sqlStr];
        }
        if (!res) {
            NSLog(@"error to insert  city");
        } else {
            NSLog(@"success to insert  city");
        }
        [db close];
    }

删除city表中,cityName为“杭州” 且cityId为“1”的字段

FMDatabase *db = [FMDatabase databaseWithPath:self.dbPath];
    if ([db open]) {
        NSString *sql = [NSString stringWithFormat:@"delete from city where cityName = '%@' and cityId = '%@'",@"杭州",@"1"];
        BOOL rs = [db executeUpdate:sql];
        if (!rs) {
            NSLog(@"error to update city");
        } else {
            NSLog(@"success to update city");
        }
        
        [db close];
    }

修改city表中,cityId为“2”的字段

FMDatabase * db = [FMDatabase databaseWithPath:self.dbPath];
    if ([db open]) {
        NSString *sqlStr = [NSString stringWithFormat:@"update city set cityName = '%@' where cityId = '2'",self.textField.text];
        BOOL res = [db executeUpdate:sqlStr];
        if (!res) {
            NSLog(@"error to insert  city");
        } else {
            NSLog(@"success to insert  city");
        }
        [db close];
    }

查询city表中的所有字段

FMDatabase *db = [FMDatabase databaseWithPath:self.dbPath];
    if ([db open]) {
        NSMutableDictionary *mutableDic = [[NSMutableDictionary alloc] init];
        NSString *sql = [NSString stringWithFormat:@"select * from city where userId = '%@'",@"123"];
        FMResultSet *rs = [db executeQuery:sql];
        while ([rs next]) {
            NSString *name = [rs stringForColumn:@"cityName"];
            NSString *cityId = [rs stringForColumn:@"cityId"];
            [mutableDic setObject:cityId forKey:name];
        }
        [db close];
        NSLog(@"%@",mutableDic);
    }

5:对查出的数据的解析

在得到查出的数据以后,需要对数据进行一些对应的解析,根据数据的类型要分别处理

/* 获取下一个记录 */
- (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;

6:数据库表的关闭

/*
关闭数据库,在你对数据库的操作完成以后要记得关闭数据库
*/
[citydb close];

三:一些注意事项

下面要讲一讲我在学习FMDB的时候遇到的一些问题,给我的感觉呢,FMDB在Xcode中编写其实还是挺糟心的。因为你会发现有时候稍微写错一点点东西,就能让你整个方法崩溃,有可能一个简单的(')就让你整句查询语句说拜拜= =,而且Xcode不会告诉你到底是哪里出了问题,这就让人很难过了,所以你能做到的只有孰能生巧,不断的让自己熟练,少犯这样的低级错误。

在执行查询语句的时候一定要用- (BOOL)next 方法,就算你只查一个数据,也一定要用

错误的示范(因为只查一个数据,所以自以为是的没用next方法,然后GG了(╯‵□′)╯︵┻━┻)

if ([db open]) {
        NSString *sql = [NSString stringWithFormat:@"select * from city where cityId = '%@'",@"2"];
        FMResultSet *rs = [db executeQuery:sql];
        NSString *name = [rs stringForColumn:@"cityName"];
        [db close];
    }

正确的姿势应该是这样的

if ([db open]) {
        NSString *sql = [NSString stringWithFormat:@"select * from city where cityId = '%@'",@"2"];
        FMResultSet *rs = [db executeQuery:sql];
        while ([rs next]) {
            NSString *name = [rs stringForColumn:@"cityName"];
        }
        [db close];
    }

另外就是,在操作数据库的时候,大家一定要注意多线程的问题
FMDatabase这个类是线程不安全的,如果在多个线程同时使用一个FMDatabase实例,会造成数据混乱问题。
为了保证线程安全,FMDB提供方便快捷的FMDatabaseQueue类,要使用这个类,需要#import导入头文件"FMDatabaseQueue.h"FMDatabaseQueue类的操作大多都和FMDatabase很相似

最后要感谢一下同事陪我把这些东西一起弄懂,也学会了挺多,阿弥陀佛~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容