将 CocoaPods 安装后,按照 CocoaPods 的使用说明就可以将 FMDB 第三方集成到工程中,具体请看博客iOS学习46之第三方CocoaPods的安装和使用(通用方法)

1. FMDB简介

 1> 概述

  • iOS 中原生的 SQLite API 在进行数据存储的时候,需要使用 C语言 中的函数,操作比较繁琐。于是,就出现了一系列将SQLite API 进行封装的库,例如 FMDB、PlausibleDatabase、SQLitePersistentObjects 等。

  • FMDB 是一款简洁、易用的封装库。因此,在这里推荐使用第三方框架 FMDB,它是对 libsqlite3 框架的封装,用起来的步骤与 SQLite 使用类似,并且它对于多线程的并发操作进行了处理,所以是线程安全的。

 2> FMDB优缺点

  • 优点:

  对多线程的并发操作进行处理,所以是线程安全的;

  以OC的方式封装了SQLite的C语言API,使用起来更加的方便;

  FMDB是轻量级的框架,使用灵活。

  • 缺点:

  因为它是OC的语言封装的,只能在iOS开发的时候使用,所以在实现跨平台操作的时候存在局限性。

 3> FMDB中重要的类

  • FMDatabase:一个 FMDatabase 对象就代表一个单独的 SQLite数据库,用来执行 SQL语句。

  • FMResultSet:使用 FMDatabase 执行查询后的结果集。

  • FMDatabaseQueue:用于在多线程中执行多个查询或更新,它是线程安全的。

 4> FMDB使用步骤

  • 第一步:使用 CocoaPods 将第三方集成到工程项目中

  • 第二步:导入 libsqlite3.0 框架,导入头文件 FMDatabase.h

  • 第三步:代码实现,与 SQLite 使用步骤相似,创建数据库路径,获得数据库路径,打开数据库,然后对数据库进行增、删、改、查操作,最后关闭数据库。

2. FMDB创建数据库和数据表

  • 第一步:获得数据库文件的路径

  创建FMDatabase对象时参数为SQLite数据库文件路径,该路径可以是以下三种方式之一:

   ① 文件路径。该文件路径无需真实存在,如果不存在会自动创建;

   ② 空字符串(@"")。表示会在临时目录创建一个空的数据库,当 FMDatabase 连接关闭时,文件也会被删除;

   ③ NULL。将创建一个内在数据库,同样的,当 FMDatabase 连接关闭时,数据将会被销毁。

  我们一般采用第一种方式来获得数据库文件的路径,具体实例代码如下:

   NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:];

    self.filePath = [documentPath stringByAppendingPathComponent:@"student.sqlite"];

    NSLog(@"filePath = %@", self.filePath);
  • 第二步:使用路径初始化FMDB对象

  使用的初始化方法:

   + (instancetype)databaseWithPath:(NSString*)aPath

  实例代码:

    // 第四步:使用路径初始化FMDB对象
self.database = [FMDatabase databaseWithPath:self.filePath];
  • 第三步:在和数据库交互之前,数据库必须是打开的。

  如果权限不足或者资源不足,则无法打开和创建数据库。

   // 需要判断数据库打开的时候才进行执行语句
   if (self.database.open) {
// 创建表
}
  • 第四步:创建表

  使用的执行SQL语句的方法:

    - (BOOL)executeUpdate:(NSString*)sql, ...

  该方法的返回值是一个BOOL值,我们可以根据返回值,来判断SQL语句是否执行成功。

  实例代码:

    if (self.database.open) {
// 建表语句
NSString *createSql = @"create table if not exists t_student(id integer primary key autoincrement not null, name text not null, age integer not null, sax text not null)";
// 执行建表语句,创建数据表
BOOL result = [self.database executeUpdate:createSql];
// 判断是否建表成功
if (result) {
NSLog(@"创表成功");
} else {
NSLog(@"创表失败");
}
}
  • 第五步:关闭数据库

  实例代码:

    // 第五步:关闭数据库
[self.database close];

3. FMDB实现增、删、改、查

 1> FMDB—执行更新

  一切不是SELECT命令的命令都视为更新。这包括CREAT,UPDATE,INSERT,ALTER,BEGIN,COMMIT,DETACH,DELETE,DROP,END,EXPLAIN,VACUUM,REPLACE等。

  简单来说,只要不是以 SELECT 开头的命令都是更新命令。

执行更新返回一个BOOL值。YES表示执行成功,否则表示有错误。你可以调用 -lastErrorMessage 和 -lastErrorCode方法来得到更多信息。

 2> 执行更新命令的相关方法

  • executeUpdate:  不确定的参数用 ? 来占位(后面参数必须是 OC 对象,;代表语句结束,也可以不写)

  增、删、改的代码实例:

// 增加(插入)数据
BOOL result = [self.database executeUpdate:@"insert into t_student(name, age, sax) values(?, ?, ?)", @"xiaoming", @, @"男"]; // 更新数据
BOOL result = [self.database executeUpdate:@"update t_student set name = ? where name = ?", @"xiaoming", @"小明"]; // 删除数据
BOOL result = [self.database executeUpdate:@"delete from t_student where name = ?", @"xiaoming"];
  • executeUpdateWithFormat:不确定的参数用%@,%d等来占位 (参数为原始数据类型,执行语句不区分大小写)

  增、删、改的代码实例:

// 增加(插入)数据
BOOL result = [self.database executeUpdateWithFormat:@"insert into t_student (name, age, sax) values (%@, %i, %@);", @"xiaoming", @, @"男"]; // 更新数据
BOOL result = [self.database executeUpdateWithFormat:@"update t_student set name = %@ where name = %@", @"xiaoming", @"小明"]; // 删除数据
BOOL result = [self.database executeUpdateWithFormat:@"delete from t_student where name = %@", @"xiaoming"];
  • executeUpdate:withArgumentsInArray:数组,直接使用数组

  增、删、改的代码实例:

// 增加(插入)数据
[self.database executeUpdate:@"insert into t_student(name, age, sax) values(?, ?, ?);" withArgumentsInArray:@[@"xiaoming", @, @"男"]]; // 更新数据
[self.database executeUpdate:@"update t_student set name = ? where name = ?;" withArgumentsInArray:@[@"xiaoming", @"小明"]]; // 删除数据
[self.database executeUpdate:@"delete from t_student where name = ?;" withArgumentsInArray:@[@"xiaoming"]];

  以上的方法大家可以根据自己的习惯和需求选择一种即可。

 3> FMDB—查询数据

  ① 概述  

  SELECT 命令就是查询,执行查询的方法是以 -excuteQuery 开头的。

  执行查询时,如果成功返回 FMResultSet 对象,错误返回 nil 。与执行更新相同,支持使用 NSError 参数。

  同时,你也可以使用 -lastErrorCode 和 -lastErrorMessage 获知错误信息。

  ② FMResultSet

  FMResultSet 提供了很多方法,来获取对应字段的信息:

    intForColumn:、longForColumn:、longLongIntForColumn:、boolForColumn:、doubleForColumn:、stringForColumn:、dataForColumn:、dataNoCopyForColumn:、UTF8StringForColumnIndex:、objectForColumn:

  ③ 执行查询语句

  查询整个表

    // 查询结果使用的类FMResultSet
FMResultSet *resultSet = [self.database executeQuery:@"select * from t_student"];

  根据条件查询

    //根据条件查询
FMResultSet *resultSet = [self.db executeQuery:@"select * from t_student where id<?;", @];

  ④ 遍历结果集合

    while (resultSet.next) {
NSInteger ID = [resultSet intForColumn:@"id"];
NSString *name = [resultSet objectForColumnName:@"name"];
NSInteger age = [resultSet intForColumn:@"age"];
NSString *sax = [resultSet objectForColumnName:@"sax"]; NSLog(@"id = %ld name = %@, age = %ld, sax = %@", ID, name, age, sax);
}

 4> 完整实例代码

#import "ViewController.h"

// 第一步:引入框架,引入支持的类库(libsqlite3.0.tbd)
#import <FMDB.h> @interface ViewController () /// 声明数据库对象
@property (nonatomic, strong) FMDatabase *database; /// 声明存储路径
@property (nonatomic, strong) NSString *filePath; @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib. [self createTabe];
} #pragma mark - 创建表
- (void)createTabe
{
// 第一步:创建sql语句
NSString *createSql = @"create table if not exists t_student(id integer primary key autoincrement not null, name text not null, age integer not null, sax text not null)"; // 第二步:找到存储路径
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:];
// NSLog(@"document = %@", documentPath);
self.filePath = [documentPath stringByAppendingPathComponent:@"student.sqlite"];
NSLog(@"filePath = %@", self.filePath); // 第三步:使用路径初始化FMDB对象
self.database = [FMDatabase databaseWithPath:self.filePath]; // 第四步:数据库执行相关的操作
// 需要判断数据库打开的时候才进行执行语句
if (self.database.open) {
BOOL result = [self.database executeUpdate:createSql];
if (result) {
NSLog(@"创表成功");
} else {
NSLog(@"创表失败");
}
} // 第五步:关闭数据库
[self.database close];
} #pragma mark - 插入
- (IBAction)insertIntoAction:(id)sender
{
// 第一步:打开数据库
[self.database open]; // 第二步:进行相关的操作
NSArray *nameArray = @[@"MBBoy", @"BoomSky", @"小明"]; for (NSString *name in nameArray) { BOOL result = [self.database executeUpdate:@"insert into t_student(name, age, sax) values(?, ?, ?)", name, @, @"男"]; // integer的数据不能在这里使用,必须使用一个对象型数据,比如NSNumber、NSString... [self.database executeUpdate:@"INSERT INTO t_student(name, age, sax) VALUES (?, ?, ?);" withArgumentsInArray:@[@"xiaoming", @, @"男"]]; if (result) {
NSLog(@"插入成功");
} else {
NSLog(@"插入失败");
}
}
[self.database close];// 更新数据// 删除数据// 增加(插入)数据
} #pragma mark - 更新
- (IBAction)updateAction:(id)sender
{
[self.database open]; BOOL result = [self.database executeUpdate:@"update t_student set name = ? where name = ?", @"xiaoming", @"小明"]; if (result) {
NSLog(@"更新成功");
} else {
NSLog(@"更新失败");
} [self.database close];
} #pragma mark - 删除
- (IBAction)deleteAction:(id)sender
{
[self.database open];
BOOL result = [self.database executeUpdate:@"delete from t_student where name = ?", @"MBBoy"];
if (result) {
NSLog(@"删除成功");
} else {
NSLog(@"删除失败");
}
[self.database close];
} #pragma mark - 查询
- (IBAction)selectAction:(id)sender
{
[self.database open]; // 查询结果使用的类FMResultSet
FMResultSet *resultSet = [self.database executeQuery:@"select * from t_student"]; // 遍历出需要的结果内容
while (resultSet.next) {
NSInteger ID = [resultSet intForColumn:@"id"];
NSString *name = [resultSet objectForColumnName:@"name"];
NSInteger age = [resultSet intForColumn:@"age"];
NSString *sax = [resultSet objectForColumnName:@"sax"]; NSLog(@"id = %ld name = %@, age = %ld, sax = %@", ID, name, age, sax);
} [self.database close];
} @end

4. FMDB实现多线程操作

 1> 概述

  • 如果应用中使用了多线程操作数据库,那么就需要使用 FMDatabaseQueue 来保证线程安全了。 应用中不可在多个线程中共同使用一个 FMDatabase 对象操作数据库,这样会引起数据库数据混乱(例如使用两个线程同时对数据库进行更新和查找)。

  • 多个线程更新相同的资源导致数据竞争时使用等待队列(等待现在执行的处理结束)。

  • 以队列的形式添加是 FMDB 比较常用的添加方式。

  • FMDB 不支持多个线程同时操作,一般使用串行方式实现相关的操作。

 2> 创建操作队列

  使用的初始化方法

+ (instancetype)databaseQueueWithPath:(NSString*)aPath

 3> 把操作打包放在操作队列中

  打包的方法

- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block

  在 Block 中添加串行队列

 4> 实例代码

#pragma mark - 以队列的形式添加很多学生
- (IBAction)insertManyStudent:(id)sender
{
// 以队列的形式添加学生是FMDB比较常用的添加方式
// FMDB不支持多个线程同时操作,一般使用串行方式实现相关的操作 [self.database open]; // 第一步:创建操作队列
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.filePath]; // 标识:记录是否操作成功
__block BOOL isSucceed = YES; // 第二步:把操作打包放在操作队列中
NSString *insertSql = @"insert into t_studen(name, age, sax) values(?, ?, ?)"; [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
// 串行队列
isSucceed &= [db executeUpdate:insertSql, @"隔壁老王", @, @"男"];
isSucceed &= [db executeUpdate:insertSql, @"Black", @, @"女"];
isSucceed &= [db executeUpdate:insertSql, @"-1", @, @"男"]; if (!isSucceed) { // block 返回的参数rollback进行处理(BOOL类型的指针)
*rollback = YES;
return;
} else {
NSLog(@"以队列的形式添加成功");
}
}]; [self.database close];
}

【原】iOS学习47之第三方-FMDB的更多相关文章

  1. IOS学习:常用第三方库(GDataXMLNode:xml解析库)

    IOS学习:常用第三方库(GDataXMLNode:xml解析库) 解析 XML 通常有两种方式,DOM 和 SAX: DOM解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过 ...

  2. 【原】iOS学习46之第三方CocoaPods的安装和使用(通用方法)

    本文主要说明CocoaPods的安装步骤.使用说明和常见的报错即解决方法. 1. CocoaPods 1>  CocoaPods简介 CocoaPods是一个用来帮助我们管理第三方依赖库的工具. ...

  3. 【原】iOS学习之Masonry第三方约束

    1.Masonry概述 目前最流行的Autolayout第三方框架 用优雅的代码方式编写Autolayout 省去了苹果官方恶心的Autolayout代码 大大提高了开发效率 框架地址:https:/ ...

  4. 【原】iOS学习之PINCache第三方缓存框架

    在项目中总是需要缓存一些网络请求数据以减轻服务器压力,业内也有许多优秀的开源的解决方案.通常的缓存方案都是由内存缓存和磁盘缓存组成的,内存缓存速度快容量小,磁盘缓存容量大速度慢可持久化. 1.PINC ...

  5. 【原】iOS学习之第三方-AFNetworking1.3.0

    将 CocoaPods 安装后,按照 CocoaPods 的使用说明就可以将 AFNetworking 第三方集成到工程中,具体请看上篇博客iOS学习46之第三方CocoaPods的安装和使用(通用方 ...

  6. iOS学习笔记(十六)——数据库操作(使用FMDB)

    iOS中原生的SQLite API在使用上相当不友好,在使用时,非常不便.于是,就出现了一系列将SQLite API进行封装的库,例如FMDB.PlausibleDatabase.sqlitepers ...

  7. 原 iOS深入学习(Block全面分析)http://my.oschina.net/leejan97/blog/268536

    原 iOS深入学习(Block全面分析) 发表于1年前(2014-05-24 16:45)   阅读(26949) | 评论(14) 39人收藏此文章, 我要收藏 赞21 12月12日北京OSC源创会 ...

  8. 【原】iOS学习之事件处理的原理

    在iOS学习23之事件处理中,小编详细的介绍了事件处理,在这里小编叙述一下它的相关原理 1.UITouch对象 在触摸事件的处理方法中都会有一个存放着UITouch对象的集合,这个参数有什么用呢? ( ...

  9. 【原】iOS学习之SQLite和CoreData数据库的比较

    1. SQLite数据库 sqlite数据库操作的基本流程是, 创建数据库, 再通过定义一些字段来定义表格结构, 可以利用sql语句向表格中插入记录, 删除记录, 修改记录, 表格之间也可以建立联系. ...

随机推荐

  1. 关于Java集合的小抄

    在尽可能短的篇幅里,将所有List.Map.Set.Queue的特征与实现方式捋一遍.适合所有"精通Java"其实还不那么自信的人阅读. List ArrayList 以数组实现. ...

  2. 自然语言27_Converting words to Features with NLTK

    https://www.pythonprogramming.net/words-as-features-nltk-tutorial/ Converting words to Features with ...

  3. asp rs开启关闭问题

    使用rs.close关闭后,可以直接用rs.open来打开数据表:如果用了set rs = nothing 从内存中清除rs对象,再次加载rs对象就需要使用set rs=server.createob ...

  4. SqlServer 产生随机数

    ALTER PROCEDURE [dbo].[usp_RandomNumber] ( , --随机数位数 --随机笔数 ) AS BEGIN DECLARE @T AS TABLE([Random N ...

  5. mysql GET DIAGNOSTICS 语法

    MySQL 5.6 提供了 get diagnostic 语句来获取错误缓冲区的内容,然后把这些内容输出到不同范围域的变量里,以便我们后续灵活操作 语法如下: GET [CURRENT] DIAGNO ...

  6. 用<forEach>遍历list集合时,提示我找不到对象的属性

    <c:forEach items="${list}" var="item"> <tr> <td>${item.UserId} ...

  7. Unity里的Mesh属性

    ----------------------------------------------------------------------------------------------- Mesh ...

  8. Zookeeper异常ConnectionLossException解决

    项目中要求做一个将配置文件读取到zookeeper节点上的工具: 开发代码如下: 但是当连接到远端的Zookeeper服务之后,出现了下面异常: Exception in thread "m ...

  9. configparser模块

    configparser模块 echo   $@ $# $? $* configparse用于处理特定格式的文件,其本质上利用open来操作文件(比如配置文件) **********配置文件***** ...

  10. Droidbox恶意软件动态分析环境搭建

    @author : Dlive 0x01 DroidBox简介 DroidBox是一款,可以获得以下信息 1.APK包hash值 2.网络通信数据 3.文件读写操作 4.网络通信,文件读写,SMS中的 ...