SQLite (http://www.sqlite.org/docs.html) 是一个轻量级的关系数据库。

iOS SDK很早就支持了SQLite,在使用时,只需要加入 libsqlite3.dylib 依赖以及引入 sqlite3.h 头文件即可。

原生的SQLite API在使用上不太友好。

于是,开源社区中就出现了一系列将SQLite API进行封装的库,而FMDB (https://github.com/ccgus/fmdb) 则是开源社区中的优秀者。

FMDB在使用上相当方便。以下是一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
NSString* docsdir = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString* dbpath = [docsdir stringByAppendingPathComponent:@"user.sqlite"];
FMDatabase* db = [FMDatabase databaseWithPath:dbpath];
[db open];
FMResultSet *rs = [db executeQuery:@"select * from people"];
while ([rs next]) {
NSLog(@"%@ %@",
[rs stringForColumn:@"firstname"],
[rs stringForColumn:@"lastname"]);
}
[db close];

可以看到,使用FMDB后的数据库代码清晰明了,比原生的API优雅多了。

FMDB同时兼容ARC和非ARC工程,会自动根据工程配置来调整相关的内存管理代码。

使用说明

手动引入相关文件或者pod引入  FMDB

 

建立数据库

建立数据库只需要如下一行即可,当该文件不存在时,fmdb会自己创建一个。如果你传入的参数是空串:@”” ,则fmdb会在临时文件目录下创建这个数据库,如果你传入的参数是 NULL,则它会建立一个在内存中的数据库。

1
FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];

打开数据库

使用如下语句,如果打开失败,可能是权限不足或者资源不足。通常打开完操作操作后,需要调用close方法来关闭数据库。

1
2
3
4
5
6
7
8
if (![db open]) {
// error
return;
}
// some operation
// ... [db close];

执行更新操作

除了Select操作之外,其它的都是更新操作。更新操作使用如下方法,如果有错误,可以用error参数中获得。

1
-[FMDatabase executeUpdate:error:withArgumentsInArray:orVAList:]

执行查询操作

查询操作示例如下。注意:即使操作结果只有一行,也需要先调用FMResultSet的next方法。

1
2
3
4
5
6
7
8
9
FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"];
while ([s next]) {
//retrieve values for each record
} FMResultSet *s = [db executeQuery:@"SELECT COUNT(*) FROM myTable"];
if ([s next]) {
int totalCount = [s intForColumnIndex:0];
}

FMDB提供如下多个方法来获取不同类型的数据:

1
2
3
4
5
6
7
8
9
10
11
intForColumn:
longForColumn:
longLongIntForColumn:
boolForColumn:
doubleForColumn:
stringForColumn:
dateForColumn:
dataForColumn:
dataNoCopyForColumn:
UTF8StringForColumnIndex:
objectForColumn:

通常情况下,你并不需要关闭FMResultSet,因为相关的数据库关闭时,FMResultSet也会被自动关闭。

数据参数

通常情况下,你可以按照标准的SQL语句,用?表示执行语句的参数,如:

1
INSERT INTO myTable VALUES (?, ?, ?)

然后,可以我们可以调用executeUpdate方法来将?所指代的具体参数传入,通常是用变长参数来传递进去的,如下:

1
2
NSString *sql = @"insert into User (name, password) values (?, ?)";
[db executeUpdate:sql, user.name, user.password];

这里需要注意的是,参数必须是NSObject的子类,所以象int,double,bool这种基本类型,需要封装成对应的包装类才行,如下所示:

1
2
3
4
// 错误,42不能作为参数
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", 42];
// 正确,将42封装成 NSNumber 类
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:42]];

线程安全

如果我们的app需要多线程操作数据库,那么就需要使用FMDatabaseQueue来保证线程安全了。 切记不能在多个线程中共同一个FMDatabase对象并且在多个线程中同时使用,这个类本身不是线程安全的,这样使用会造成数据混乱等问题。

使用FMDatabaseQueue很简单,首先用一个数据库文件地址来初使化FMDatabaseQueue,然后就可以将一个闭包(block)传入inDatabase方法中。 在闭包中操作数据库,而不直接参与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
// 创建,最好放在一个单例的类中
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; // 使用
[queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; FMResultSet *rs = [db executeQuery:@"select * from foo"];
while ([rs next]) {
// …
}
}]; // 如果要支持事务
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; if (whoopsSomethingWrongHappened) {
*rollback = YES;
return;
}
// etc…
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]];
}];

工具

为了查看Sqlite中的数据,一个好的图形化界面的数据库管理程序是必不可少的。mysql有phpMyAdmin,那么sqlite呢?

我主要使用的是Firefox的一个名为SQLite Manager的插件,安装此插件后,可以直接打开后缀名为sqlite的数据库文件。SQLite Manager提供一个图形化的界面来执行数据查询或更改操作。如下图所示:

总结

FMDB将SQLite API进行了很友好的封装,使用上非常方便,对于那些使用纯Sqlite API来进行数据库操作的app,可以考虑将其迁移到基于FMDB上,这对于以后数据库相关功能的开发维护,可以提高不少效率。

上文部分内容参考并借用自唐巧

代码传送门:https://github.com/tangqiaoboy/FmdbSample

其他传送门:

https://blog.csdn.net/lykio_881210/article/details/80267500

https://www.jianshu.com/p/859243acb24b

https://www.cnblogs.com/zhw511006/archive/2012/03/14/2397108.html

https://blog.csdn.net/qq_33701006/article/details/51836914

https://www.jianshu.com/p/ea282cc0f011

https://www.cnblogs.com/pretty-guy/p/4065014.html

https://www.aliyun.com/jiaocheng/354992.html

https://www.jianshu.com/p/84bd6b8ac94c

https://blog.csdn.net/yi_zz32/article/details/52669977

看完了以上文章,还有需要讨论的  欢迎留言

本人的博客不定期更新,本文上次更新时间:201812

最新文章

  1. iOS学习-KVO设计模式
  2. caffe model 可视化
  3. mac--又发现了一款mac快捷键神器
  4. Windows Azure 使用体验
  5. java中图片文件的传输及显示(Socket以及ServerSocket演示)
  6. Autofac全面解析系列(版本:3.5) – [使用篇(推荐篇):2.解析获取]
  7. C语言--指针问题_1
  8. Go 支持Protocol Buffers的配置
  9. SqlServer之游标深入
  10. Cocoa 框架为什么采用两阶段的方式来创建对象?
  11. 介绍 32 位和 64 位版本的 Microsoft Office 2010
  12. iOS 网络错误-分类
  13. java中的数组二分法
  14. Educational Codeforces Round 58 (Rated for Div. 2) F dp + 优化(新坑) + 离线处理
  15. dell T130服务器加内存
  16. 5.05-requests_cookies2
  17. markdown简单常用语法
  18. 20155209林虹宇 Exp7 网络欺诈防范
  19. Win 2008 r2 远程桌面多用户登陆,一用户多登陆配置
  20. UVA-10273 Cyborg Genes (DP)

热门文章

  1. 对于运用git将本地文件上传到coding总结
  2. Pycharm脚本通用部分设置
  3. String、StringBuffer和StringBuilder,定义一个自己的StringBuilder的类
  4. struts拦截器详解
  5. 【bzoj4260】Codechef REBXOR Trie树
  6. [AtCoderContest015D]A or...or B Problem
  7. [POI2005]SKA-Piggy Banks (Tarjan缩点)
  8. offsetWidth clientWidth scrollWidth 三者之间的区别和联系
  9. 在 NetBeans 中开发一般 Java 应用程序时配置 Allatori 进行代码混淆
  10. 推荐!手把手教你使用Git(转)